28/01/2014 MCAFEE SECURE 認證的網站

https://www.mcafeesecure.com/RatingVerify?ref=www.HongKongCupid.com

2013年6月19日 星期三

**SMASHING MAGAZINE's*^How to Design A Moblie Game With HTML5**~!

**SMASHING MAGAZINE's*^How to Design A Moblie Game With HTML5**~!

*A handful of game developers are pushing the envelope of mobile HTML5 games at the moment. Check out the likes of   Nutmeg and Lunch Bug for some shining examples. The great thing about these titles is that they work equally well on         both mobile and desktop using the same code.  
Could HTML5 finally fulfill the holy grail of “write once, run anywhere”?*

*Getting Started
Before you start sketching the next Temple 
 Run or Angry Birds, you should be aware of  
 a few things that could  
dampen your excitement:  *

*Performance 
Mobile browsers are not traditionally 
known for their blazing JavaScript  
engines. With iOS 6 and Chrome beta  
for Android, though,  
 things are improving fast.
  • Resolution
    A veritable cornucopia of Android 
  • devices sport a wide range of   
  • resolutions. Not to mention the  
  •  increased resolution and pixel density 
  • of the iPhone 4 and iPad 3         *
  • *Audio
    Hope you enjoy the sound of silence.
    Audio support in mobile browsers is poor,
     to say the least. Lag is a major problem,
    as is the fact that most devices offer only
     a single channel. iOS won’t even load a    
    sound until the user initiates the action.   
    My advice is to hold tight and wait for    
    browser vendors to sort this out.                *
    *
    Now, as a Web developer you’re used to
     dealing with the quirks of certain      
    browsers and degrading gracefully and   
    dealing with fragmented platforms. So,  
    a few technical challenges won’t put you 
    off, right? What’s more, all of these     
    performance and audio problems are    
    temporary. The mobile browser landscape 
    is changing so quickly that these concerns 
    will soon be a distant memory.
    In this tutorial, we’ll make a relatively  
    simple game that takes you through the  
    basics and steers you away from pitfalls.
    The result will look like this:                         *

    *
    Screenshot of finished demo*

    *
  • Play the demo. 5
  • Download the demo  (ZIP).   *

  • *It’s a fairly simple game, in which the 
    user bursts floating bubbles before they 
    reach the top of the screen. Imaginatively, 
     I’ve titled our little endeavour Pop.        *
    *We’ll develop this in a number  
     of distinct stages:                     *

    *
    1. Cater to the multitude of viewports
    2. and optimize for mobile;
    3. Look briefly at using the canvas API
    4. to draw to the screen;
    5. Capture touch events;
    6. Make a basic game loop;
    7. Introduce sprites, or game “entities”;
    8. Add collision detection and some
    9. simple maths to spice things up;
    10. Add a bit of polish and some basic
    11. particle effects.    *
    *1. Setting The Stage
    Enough of the background story. Fire up
     your favorite text editor, pour a strong
    brew of coffee, and let’s get our 
    hands dirty.
    As mentioned, there is a plethora of  
    resolution sizes and pixel densities    
    across devices. This means we’ll have to  
    scale our canvas to fit the viewport.  
    This could come at the price of a loss 
    in quality, but one clever trick is to make  
    the canvas small and then scale up, which  
     provides a performance boost.
    Let’s kick off with a basic HTML shim:         *
    *
    <!DOCTYPE HTML>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    
    <meta name="viewport" content=
    "width=device-width, 
    
        user-scalable=no, initial-scale=1, 
    maximum-scale=1, user-scalable=0" /> 
    
    <meta name="apple-mobile-web-app-
    capable" content="yes" /> 
    
    <meta name="apple-mobile-web-app-
    status-bar-style" content="black-translucent" /> 
    
    <style type="text/css">
    body { margin: 0; padding: 0; background: #000;} 
    canvas { display: block; margin: 0 auto; 
     background: #fff; } 
    
    </style>
    
    </head>
    
    <body>
    
    <canvas> </canvas>
    <script>
    // all the code goes here 
    </script>
    
    </body> 
    </html> 
    The meta viewport tag tells mobile  
     browsers to disable user scaling and to
     render at full size rather than shrink   
    the page down.
    The subsequent apple-    prefixed meta  
    tags allow the game to be bookmarked. 
    On the iPhone, bookmarked apps do not 
    display the toolbar at the bottom of the
     page, thus freeing up valuable real estate.
    Take a look at the following:                  *

    *
    // namespace our game 
    var POP = { 
    
        // set up some initial values 
        WIDTH: 320, 
        HEIGHT:  480, 
        // we'll set the rest of these 
        // in the init function 
        RATIO:  null,
        currentWidth:  null,
        currentHeight:  null,
        canvas: null,
        ctx:  null,
    
        init: function() { 
    
            // the proportion of width to height 
            POP.RATIO = POP.WIDTH / POP.HEIGHT;
            // these will change when the 
    screen is resized
            POP.currentWidth = POP.WIDTH;
            POP.currentHeight = POP.HEIGHT;
            // this is our canvas element
            POP.canvas = document.
    getElementsByTagName('canvas')[0];
            // setting this is important 
            // otherwise the browser will 
            // default to 320 x 200 
            POP.canvas.width = POP.WIDTH; 
            POP.canvas.height = POP.HEIGHT; 
            // the canvas context enables us to 
            // interact with the canvas api 
            POP.ctx = POP.canvas.getContext('2d'); 
    
            // we're ready to resize 
            POP.resize(); 
    
        }, 
    
        resize: function() { 
    
            POP.currentHeight = window.innerHeight;
            // resize the width in proportion
            // to the new height
            POP.currentWidth =
     POP.currentHeight * POP.RATIO;
    
            // this will create some extra 
    space on the
            // page, allowing us to scroll past
            // the address bar, thus hiding it.
            if (POP.android || POP.ios) {
                document.body.style.height =
     (window.innerHeight + 50) + 'px';
            }
    
            // set the new canvas style 
    width and height
            // note: our canvas is still 
    320 x 480, but
            // we're essentially scaling 
    it with CSS
            POP.canvas.style.width =
     POP.currentWidth + 'px';
            POP.canvas.style.height =
     POP.currentHeight + 'px';
    
            // we use a timeout here because 
    some mobile
            // browsers don't fire if there is not 
            // a short delay 
            window.setTimeout(function() { 
                    window.scrollTo(0,1); 
            }, 1);
        } 
    
    };
    
    window.addEventListener 
    ('load', POP.init, false); 
    window.addEventListener 
    ('resize', POP.resize, false); 
    First, we create the POP namespace for
     our game. Being good developers,   
    we don’t want to pollute the global 
    namespace. In keeping good practice, 
     we will declare all variables at the  
    start of the program.
    Most of them are obvious: canvas  
    refers to the canvas    element in the HTML,
     and ctx    enables us to access it via the   
    JavaScript canvas API. 
    In POP.init,    we grab a reference to
    our canvas element, get its context 
    and adjust the canvas element’s     
    dimensions to 480 × 320.
     The resize     function, which is fired on 
    resize and load events, adjusts the  
     canvas’ style    attribute for width and
    height accordingly while maintaining 
    the ratio. Effectively, the canvas is   
    still the same dimensions but has been 
    scaled up using CSS. Try resizing your  
    browser and you’ll see the canvas scale to fit.
    If you tried that on your phone, you’ll 
     notice that the address bar is still     
    visible. Ugh! We can fix this by adding 
    a few extra pixels to the document and 
    then scrolling down to hide  
    the address bar, like so: 
    // we need to sniff out Android and iOS
    // so that we can hide the address bar in
    // our resize function
    POP.ua = navigator.userAgent.toLowerCase();
    
    POP.android = POP.ua.indexOf('android') >
     -1 ? true : false;
    
    POP.ios = ( POP.ua.indexOf('iphone') >
     -1 || POP.ua.indexOf('ipad') > -1  ) ? 
        true : false;
    The code above sniffs out the user
    agent, flagging for Android and iOS
    if present. Add it at the end of POP.init
    before the call to POP.resize().             *

    *Then, in the resize    function,
     if android    or ios    is true,    we add  
    another 50 pixels to the document’s  
    height — i.e. enough extra space to be 
    able to scroll down past the address bar.
    // this will create some extra space on the 
    // page, enabling us to scroll past 
    // the address bar, thus hiding it. 
    if (POP.android || POP.ios) { 
        document.body.style.height =
     (window.innerHeight + 50) + 'px';
    } 
    Notice that we do this only for Android
    and iOS devices; otherwise,
     nasty scroll bars will appear. Also,
     we need to delay the firing of scrollTo   
    to make sure it doesn’t get ignored  
    on mobile Safari.  *

    *2. A Blank Canvas
    Now that we’ve scaled our canvas  
    snuggly to the viewport, let’s add   
    the ability to draw some shapes.
    *Note: In this tutorial, we’re going to 
     stick with basic geometric shapes.  
    iOS 5 and Chrome beta for Android can 
     handle a lot of image sprites at a high 
    frame rate. Try that on Android 3.2 or  
    lower and the frame rate will 
    drop exponentially.
     Luckily, there is not much overhead 
    when drawing circles,
     so we can have a lot of bubbles in our 
    game without hampering performance   
    on older devices.
    Below, we’ve added a basic Draw    object  
    that allows us to clear the screen, draw a 
    rectangle and circle, and add some text.
    Nothing mind-blowing yet.  
    Mozilla Developers Network has excellent  
     resources as always,   

    *
    // abstracts various canvas operations into 
    // standalone functions 
    POP.Draw = { 
    
        clear: function() { 
            POP.ctx.clearRect 
    (0, 0, POP.WIDTH, POP.HEIGHT); 
        },
    
        rect: function(x, y, w, h, col) { 
            POP.ctx.fillStyle = col;
            POP.ctx.fillRect(x, y, w, h);
        },
    
        circle: function(x, y, r, col) { 
            POP.ctx.fillStyle = col;
            POP.ctx.beginPath();
            POP.ctx.arc 
    (x + 5, y + 5, r, 0,  Math.PI * 2, true);
            POP.ctx.closePath(); 
            POP.ctx.fill(); 
        },
    
        text: function(string, x, y, size, col) { 
            POP.ctx.font =
     'bold '+size+'px Monospace'; 
            POP.ctx.fillStyle = col; 
            POP.ctx.fillText(string, x, y); 
        } 
    
    };
    Our Draw object has methods for clearing 
     the screen and drawing rectangles, 
     circles and text.  
    The benefit of abstracting these  
    operations is that we don’t have to  
    remember the exact canvas API calls,
     and we can now draw a circle with  
    one line of code, rather than five.
    Let’s put it to the test: 
    // include this at the end of POP.init function 
    POP.Draw.clear(); 
    POP.Draw.rect(120,120,150,150, 'green'); 
    POP.Draw.circle(100, 100, 50, 'rgba(255,0,0,0.5)');
    POP.Draw.text('Hello World', 100, 100, 10, '#000');
    Include the code above at the end  
    of the POP.init        
    function, and you should see a couple 
    of shapes drawn to the canvas.

    3. The Magic Touch 

    Just as we have the click event, 
    mobile browsers provide methods 
     for catching touch events.
    The interesting parts of the code below
     are the touchstart, touchmove     
    and touchend                   events.
    With the standard click      event, we can
     get the coordinates from e.pageX    
    and e.pageY.     Touch events are slightly 
     different. They contain a touches     
    array, each element of which contains  
     touch coordinates and other data.
    We only want the first touch,
     and we access it like so: e.touches[0].    
    Note: Android provides JavaScript   
    access to multi-touch actions only  
    since version 4.
    We also call e.preventDefault();     when
    each event is fired to disable scrolling,
     zooming and any other action that  
    would interrupt the flow of the game.
    Add the following code  
    to the POP.init      function.
    // listen for clicks 
    window.addEventListener('click', function(e) { 
        e.preventDefault(); 
        POP.Input.set(e); 
    }, false); 
    
    // listen for touches 
    window.addEventListener('touchstart', function(e) { 
        e.preventDefault(); 
        // the event object has an array 
        // named touches; we just want 
        // the first touch 
        POP.Input.set(e.touches[0]);
    }, false);
    window.addEventListener('touchmove', function(e) { 
        // we're not interested in this,
        // but prevent default behaviour 
        // so the screen doesn't scroll 
        // or zoom 
        e.preventDefault();
    }, false); 
    window.addEventListener('touchend', function(e) { 
        // as above 
        e.preventDefault(); 
    }, false); 
    You probably noticed that the code  
    above passes the event data to   
    an Input object, which we’ve yet 
     to define. Let’s do that now:
    // + add this at the bottom of your code,
    // before the window.addEventListeners 
    POP.Input = { 
    
        x: 0,
        y: 0,
        tapped :false,
    
        set: function(data) { 
            this.x = data.pageX; 
            this.y = data.pageY; 
            this.tapped = true; 
    
            POP.Draw.circle 
    (this.x, this.y, 10, 'red'); 
        } 
    
    };
    Now, try it out. Hmm, the circles are 
    not appearing. A quick scratch of the 
    head and a lightbulb moment! Because
     we’ve scaled the canvas, we need to  
    account for this when mapping the  
    touch to the screen’s position.
    First, we need to subtract the offset  
    from the coordinates.
    var offsetTop = POP.canvas.offsetTop, 
        offsetLeft = POP.canvas.offsetLeft; 
    
    this.x = data.pageX - offsetLeft; 
    this.y = data.pageY - offsetTop;                      *
     
    *Diagram showing canvas offset relative to the browser window*
    *
    Then, we need to take into account the
    factor by which the canvas has been
    scaled so that we can plot to the actual
    canvas (which is still 320 × 480).
    var offsetTop = POP.canvas.offsetTop,
        offsetLeft = POP.canvas.offsetLeft;
        scale = POP.currentWidth / POP.WIDTH; 
    
    this.x = ( data.pageX - offsetLeft ) / scale; 
    this.y = ( data.pageY - offsetTop ) / scale;             *
     
    *Difference between CSS scaled canvas and actual dimensions *

    *
    If your head is starting to hurt, a practical
    example should provide some relief. Imagine
    the player taps the 500 × 750 canvas above
    at 400,400. We need to translate that
    to 480 × 320 because, as far as the JavaScript
    is concerned, those are the dimensions of the
    canvas. So, the actual x coordinate is 400
    divided by the scale; in this case
    , 400 ÷ 1.56 = 320.5.
    Rather than calculating this on each touch
    event, we can calculate them after resizing.
    Add the following code to the start of the
    program, along with the other
    variable declarations:
    // let's keep track of scale 
        // along with all initial declarations 
        // at the start of the program 
        scale:  1,
        // the position of the canvas 
        // in relation to the screen 
        offset = {top: 0, left: 0}, 
    In our resize function, after adjusting the
    canvas’ width and height, we make note of
    the current scale and offset:
    // add this to the resize function.
    POP.scale = POP.currentWidth / POP.WIDTH; 
    POP.offset.top = POP.canvas.offsetTop; 
    POP.offset.left = POP.canvas.offsetLeft; 
    Now, we can use them in the set method of
    our POP.Input class:
    this.x = 
    (data.pageX - POP.offset.left) / POP.scale; 
    this.y = 
    (data.pageY - POP.offset.top) / POP.scale;              *
     
    **

    4. In The Loop

    A typical game loop goes something like this:
    1. Poll user input,
    2. Update characters and process collisions,
    3. Render characters on the screen,
    4. Repeat.
    We could, of course, use setInterval, but
    there’s a shiny new toy in town named
    requestAnimationFrame. It promises smoother
    animation and is more battery-efficient.
    The bad news is that it’s not supported
    consistently across browsers. But Paul Irish
    has come to the rescue with a handy shim.
    Let’s go ahead and add the shim to the start
    of our current code base.
    // http://paulirish.com/2011/ 
    requestanimationframe-for-smart-animating 
    // shim layer with setTimeout fallback 
    window.requestAnimFrame = (function(){
      return  window.requestAnimationFrame       || 
              window.webkitRequestAnimationFrame || 
              window.mozRequestAnimationFrame    || 
              window.oRequestAnimationFrame      || 
              window.msRequestAnimationFrame     || 
              function( callback ){ 
                window.setTimeout 
    (callback, 1000 / 60); 
              }; 
    })(); 
    And let’s create a rudimentary game loop:
    // Add this at the end of POP.init; 
    // it will then repeat continuously 
    POP.loop(); 
    
    // Add the following functions after POP.init: 
    
    // this is where all entities will be moved 
    // and checked for collisions, etc.
    update: function() { 
    
    },
    
    // this is where we draw all the entities 
    render: function() { 
    
       POP.Draw.clear(); 
    },
    
    // the actual loop 
    // requests animation frame, 
    // then proceeds to update 
    // and render 
    loop: function() { 
    
        requestAnimFrame( POP.loop ); 
    
        POP.update(); 
        POP.render(); 
    } 
    We call the loop at the end of POP.init.
    The POP.loop function in turn calls our POP.
    update and POP.render methods.
    requestAnimFrame ensures that the loop is
    called again, preferably at 60 frames per
    second. Note that we don’t have to worry
    about checking for input in our loop because
    we’re already listening for touch and click
    events, which is accessible through our POP.
    Input class.
    The problem now is that our touches from the
    last step are immediately wiped off the screen.
    We need a better approach to remember what was
    drawn to the screen and where. **

    *

    5. Spritely Will Do It

    First, we add an entity array to keep track
    of all entities. This array will hold a
    reference to all touches, bubbles,
    particles and any other dynamic thing we
    want to add to the game.
    // put this at start of program 
    entities: [], 
    Let’s create a Touch class that draws a
    circle at the point of contact, fades it out
    and then removes it.
    POP.Touch = function(x, y) { 
    
        this.type = 'touch';    // we'll 
    need this later 
        this.x = x;             // the x coordinate 
        this.y = y;             // the y coordinate 
        this.r = 5;             // the radius 
        this.opacity = 1;       // initial 
    opacity; the dot will fade out 
        this.fade = 0.05;       // amount by
     which to fade on each game tick 
        this.remove = false;    // flag for
     removing this entity. POP.update 
                                // will take
     care of this 
    
        this.update = function() { 
            // reduce the opacity accordingly  
            this.opacity -= this.fade; 
            // if opacity if 0 or less, 
     flag for removal 
            this.remove =
     (this.opacity < 0) ? true : false; 
        }; 
    
        this.render = function() { 
            POP.Draw.circle
    (this.x, this.y, this.r, 'rgba
    (255,0,0,'+this.opacity+')'); 
        }; 
    
    }; 
    The Touch class sets a number of properties
    when initiated. The x and y coordinates are
    passed as arguments, and we set the radius
    this.r to 5 pixels. We also set an initial
    opacity to 1 and the rate by which the
    touch fades to 0.05. There is also a remove
    flag that tells the main game loop whether
    to remove this from the entities array.
    Crucially, the class has two main methods:
    update and render. We will call these from
    the corresponding part of our game loop.
    We can then spawn a new instance of Touch in
    the game loop, and then move them via
    the update method:
    // POP.update function 
    update: function() { 
    
        var i; 
    
        // spawn a new instance of Touch 
        // if the user has tapped the screen 
        if (POP.Input.tapped) { 
            POP.entities.push(new POP.Touch 
    (POP.Input.x, POP.Input.y)); 
            // set tapped back to false 
            // to avoid spawning a new touch 
            // in the next cycle 
            POP.Input.tapped = false; 
        } 
    
        // cycle through all entities and  
    update as necessary 
        for (i = 0; i < POP.entities.
    length; i += 1) { 
            POP.entities[i].update(); 
    
            // delete from array if remove property 
            // flag is set to true 
            if (POP.entities[i].remove) { 
                POP.entities.splice(i, 1); 
            } 
        } 
    
    }, 
    Basically, if POP.Input.tapped is true,
    then we add a new instance of POP.Touch to
    our entities array. We then cycle through the
    entities array, calling the update method
    for each entity. Finally, if the entity is
    flagged for removal, we delete it from the array.
    Next, we render them in the POP.render function.
    // POP.render function 
    render: function() { 
    
        var i; 
    
       POP.Draw.rect(0, 0, POP.WIDTH, 
     POP.HEIGHT, '#036');
    
        // cycle through all entities and  
    render to canvas 
        for (i = 0; i < POP.
    entities.length; i += 1) { 
            POP.entities[i].render(); 
        } 
    
    }, 
    Similar to our update function, we cycle
    through the entities and call their render
    method to draw them to the screen.
    So far, so good. Now we’ll add a Bubble class
    that will create a bubble that floats up for
    the user to pop.
    POP.Bubble = function() { 
    
        this.type = 'bubble'; 
        this.x = 100; 
        this.r =
     5;                // the radius of the bubble 
        this.y = POP.HEIGHT +
     100; // make sure it starts off screen 
        this.remove = false; 
    
        this.update = function() { 
    
            // move up the screen by 1 pixel 
            this.y -= 1; 
    
            // if off screen, flag for removal 
            if (this.y < -10) { 
                this.remove = true; 
            } 
    
        }; 
    
        this.render = function() { 
    
            POP.Draw.circle 
    (this.x, this.y, this.r, 'rgba(255,255,255,1)'); 
        }; 
    
    }; 
    The POP.Bubble class is very similar to the
    Touch class, the main differences being that
    it doesn’t fade but moves upwards. The motion
    is achieved by updating the y position,
    this.y, in the update function. Here, we also
    check whether the bubble is off screen; if so,
    we flag it for removal.
    Note: We could have created a base Entity class
    that both Touch and Bubble inherit from. But,
    I’d rather not open another can of worms about
    JavaScript prototypical inheritance versus
    classic at this point.
    // Add at the start of the program 
    // the amount of game ticks until 
    // we spawn a bubble 
    nextBubble: 100, 
    
    // at the start of POP.update 
    // decrease our nextBubble counter 
    POP.nextBubble -= 1; 
    // if the counter is less than zero 
    if (POP.nextBubble < 0) { 
        // put a new instance of bubble into 
     our entities array 
        POP.entities.push(new POP.Bubble());
         // reset the counter with a random value 
        POP.nextBubble =
     ( Math.random() * 100 ) + 100; 
    } 
    Above, we have added a random timer to our
    game loop that will spawn an instance of
    Bubble at a random position. At the start
    of the game, we set nextBubble with a value
    of 100. This is subtracted on each game tick
    and, when it reaches 0, we spawn a bubble and
    reset the nextBubble counter.

    6. Putting It Together

    First of all, there is not yet any notion of
    collision detection. We can add that with a
    simple function. The math behind this is
    basic geometry, which you can
    // this function checks if two circles overlap 
    POP.collides = function(a, b) { 
    
            var distance_squared =
     ( ((a.x - b.x) * (a.x - b.x)) + 
                                    ((a.y - b.y)
     * (a.y - b.y))); 
    
            var radii_squared =
     (a.r + b.r) * (a.r + b.r); 
    
            if (distance_squared < radii_squared) { 
                return true; 
            } else { 
                return false; 
            } 
    }; 
    
    // at the start of POP.update, we set a  
    flag for checking collisions 
        var i, 
            checkCollision = false; // we only 
     need to check for a collision
                                    // if the user
     tapped on this game tick
    
    // and then incorporate into the main logic 
    
    if (POP.Input.tapped) { 
        POP.entities.push(new POP.Touch 
    (POP.Input.x, POP.Input.y)); 
        // set tapped back to false 
        // to avoid spawning a new touch 
        // in the next cycle 
        POP.Input.tapped = false; 
        checkCollision = true; 
    
    } 
    
    // cycle through all entities and  
    update as necessary 
    for (i = 0; i < POP.entities.length; i += 1) { 
        POP.entities[i].update();
    
        if (POP.entities[i].type ===
     'bubble' && checkCollision) {
            hit = POP.collides(POP.entities[i], 
                                {x: POP.Input. 
    x, y: POP.Input.y, r: 7});
            POP.entities[i].remove = hit; 
        } 
    
        // delete from array if remove property 
        // is set to true
        if (POP.entities[i].remove) { 
            POP.entities.splice(i, 1); 
        } 
    } 
    The bubbles are rather boring; they all
    travel at the same speed on a very predictable
    trajectory. Making the bubbles travel at
    random speeds is a simple task:
    POP.Bubble = function() { 
    
        this.type = 'bubble'; 
        this.r = (Math.random() * 20) + 10; 
        this.speed = (Math.random() * 3) + 1; 
    
        this.x = (Math.
    random() * (POP.WIDTH) - this.r); 
        this.y = POP.HEIGHT +
     (Math.random() * 100) + 100; 
    
        this.remove = false; 
    
        this.update = function() { 
    
            this.y -= this.speed; 
    
        // the rest of the class is unchanged 
    And let’s make them oscillate from side to
    side, so that they are harder to hit:
    // the amount by which the bubble 
        // will move from side to side 
        this.waveSize = 5 + this.r; 
        // we need to remember the original 
        // x position for our sine wave calculation 
        this.xConstant = this.x; 
    
        this.remove = false; 
    
        this.update = function() { 
    
            // a sine wave is commonly a 
     function of time 
            var time = new Date().getTime() * 0.002; 
    
            this.y -= this.speed;
            // the x coordinate to follow a sine wave 
            this.x = this.waveSize *
     Math.sin(time) + this.xConstant; 
    
        // the rest of the class is unchanged 
    Again, we’re using some basic geometry to
    achieve this effect; in this case, a sine wave.
    While you don’t need to be a math whiz to
    make games, basic understanding goes a long way.
    The article
    Animations With JavaScript"

    should get you started.
    Let’s also show some statistics on screen.
    To do this, we will need to track various
    actions throughout the game.
    Put the following code, along with all of
    the other variable declarations, at the beginning
    of the program.
    // this goes at the start of the program 
    // to track players's progress 
    POP.score = { 
        taps: 0, 
        hit: 0, 
        escaped: 0, 
        accuracy: 0 
    }, 
    Now, in the Bubble class we can keep track
    of POP.score.escaped when a bubble goes off screen.
    // in the bubble class, when a bubble makes it to 
    // the top of the screen
        if (this.y < -10) {
            POP.score.escaped += 1; // update score
            this.remove = true;
        } 
    In the main update loop, we increase POP.
    score.hit accordingly:
    // in the update loop 
    if (POP.entities[i].type ===
     'bubble' && checkCollision) { 
        hit = POP.collides(POP.entities[i], 
                            {x: POP.Input.x, y: POP.
    Input.y, r: 7});
        if (hit) { 
            POP.score.hit += 1; 
        } 
    
        POP.entities[i].remove = hit; 
    } 
    In order for the statistics to be accurate,
    we need to record all of the taps
    the user makes:
    // and record all taps 
    if (POP.Input.tapped) { 
        // keep track of taps; needed to 
        // calculate accuracy 
        POP.score.taps += 1; 
    Accuracy is obtained by dividing the number
    of hits by the number of taps,
    multiplied by 100, which gives us a nice
    percentage. Note that ~~(POP.score.accuracy)
    is a quick way (i.e. a hack) to round floats
    down to integers.
    // Add at the end of the update loop 
    // to calculate accuracy 
    POP.score.accuracy =
     (POP.score.hit / POP.score.taps) * 100; 
    POP.score.accuracy = isNaN(POP.score.accuracy) ? 
        0 :
        ~~(POP.score.accuracy); 
     // a handy way to round floats
    Lastly, we use our POP.Draw.text to display
    the scores in the main update function.
    // and finally in the draw function 
    POP.Draw.text
    ('Hit: ' + POP.score.hit, 20, 30, 14, '#fff'); 
    POP.Draw.text
    ('Escaped: ' + POP.score.escaped,
     20, 50, 14, '#fff'); 
    POP.Draw.text
    ('Accuracy: ' + POP.score.accuracy +
     '%', 20, 70, 14, '#fff'); 

    7. Spit And Polish

    There’s a common understanding that a
    playable demo can be made in a couple of hours,
    but a polished game takes days, week,
    months or even years!
    We can do a few things to improve the visual
    appeal of the game.

    Particle Effects

    Most games boast some form of particle
    effects, which are great for explosions.
    What if we made a bubble explode into many
    tiny bubbles when it is popped, rather than
    disappear instantly?
    Take a look at our Particle class:
    POP.Particle = function(x, y,r, col) { 
    
        this.x = x; 
        this.y = y; 
        this.r = r; 
        this.col = col; 
    
        // determines whether particle will 
        // travel to the right of left 
        // 50% chance of either happening 
        this.dir =
     (Math.random() * 2 > 1) ? 1 : -1; 
    
        // random values so particles do not 
        // travel at the same speeds 
        this.vx = ~~(Math.random() * 4) * this.dir; 
        this.vy = ~~(Math.random() * 7); 
    
        this.remove = false; 
    
        this.update = function() { 
    
            // update coordinates 
            this.x += this.vx; 
            this.y += this.vy; 
    
            // increase velocity so particle 
            // accelerates off screen 
            this.vx *= 0.99; 
            this.vy *= 0.99; 
    
            // adding this negative amount to the 
            // y velocity exerts an upward pull on 
            // the particle, as if drawn to the 
            // surface 
            this.vy -= 0.25;
    
            // off screen 
            if (this.y < 0) { 
                this.remove = true; 
            } 
    
        };
    
        this.render = function() { 
            POP.Draw.circle 
    (this.x, this.y, this.r, this.col); 
        }; 
    
    }; 
    It’s fairly obvious what is going on here.
    Using some basic acceleration so that the
    particles speed up as the reach the surface
    is a nice touch. Again, this math and physics
    are beyond the scope of this article, but for
    those interested,
    To create the particle effect, we push several
    particles into our entities array
    whenever a bubble is hit:
    // modify the main update function like so: 
    if (hit) { 
        // spawn an explosion 
        for (var n = 0; n < 5; n +=1 ) { 
            POP.entities.push(new POP.Particle( 
                POP.entities[i].x, 
                POP.entities[i].y, 
                2, 
                // random opacity to 
     spice it up a bit
                'rgba
    (255,255,255,'+Math.random()*1+')'
            )); 
        } 
        POP.score.hit += 1; 
    } 

    Waves

    Given the underwater theme of the game,
    adding a wave effect to the top of the screen would be a nice touch. We can do this by drawing a number of overlapping circles to give the illusion of waves:
    // set up our wave effect; 
    // basically, a series of overlapping circles 
    // across the top of screen 
    POP.wave = { 
        x: -25, // x coordinate of first circle 
        y: -40, // y coordinate of first circle 
        r: 50, // circle radius 
        time: 0, // we'll use this in 
    calculating the sine wave 
        offset: 0 // this will be the
     sine wave offset 
    }; 
    // calculate how many circles we need to 
    // cover the screen's width
    POP.wave.total =
     Math.ceil(POP.WIDTH / POP.wave.r) + 1; 
    Add the code above to the POP.init function.
    POP.wave has a number of values that we’ll
    need to draw the waves.
    Add the following to the main update function.
    It uses a sine wave to adjust the position of
    the waves and give the illusion of movement.
    // update wave offset 
    // feel free to play with these values for 
    // either slower or faster waves 
    POP.wave.time = new Date().getTime() * 0.002; 
    POP.wave.offset =
     Math.sin(POP.wave.time * 0.8) * 5; 
    All that’s left to be done is to draw the waves,
    which goes into the render function.
    // display snazzy wave effect 
    for (i = 0; i < POP.wave.total; i++) { 
    
        POP.Draw.circle(
                    POP.wave.x + POP.wave.
    offset +  (i * POP.wave.r), 
                    POP.wave.y,
                    POP.wave.r, 
                    '#fff'); 
    } 
    Here, we’ve reused our sine wave solution for
    the bubbles to make the waves move gently to
    and fro. Feeling seasick yet?

    Final Thoughts

    Phew! That was fun. Hope you enjoyed this short
    forage into tricks and techniques for making
    an HTML5 game. We’ve managed to create a very
    simple game that works on most smartphones as
    well as modern browsers. Here are some things
    you could consider doing:
    • Store high scores using local storage.
    • Add a splash screen and a “Game over” screen.
    • Enable power-ups.
    • Add audio. Contrary to what I said at the
    • beginning of this article, this isn’t
    • , just a bit of a headache. One technique is
    • to use audio sprites (kind of like CSS image
    • sprites); Remy Sharp breaks it down 6.
    • Let your imagination run wild!
    If you are interested in further exploring the
    possibilities of mobile HTML5 games,
    I recommend test-driving a couple of frameworks
    to see what works for you. Juho Vepsäläinen
    If you’re willing to invest a little cash,
    then Impact is a great starting point, with
    thorough documentation and lively helpful forums.
    And the impressive X-Type demonstrates what is
    possible. Not bad, eh?
    (al) (jc) *

    &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

    2013年6月18日 星期二

    **ASP內建元件與物件 **

    **ASP內建元件與物件 **
    *ASP的輸入 *&*Request物件*
    *Request 物件 :Request 物件與Response 物件是一對的的,為何如此
    說呢?因為Response 物件是回應資料給瀏覽器,
    而Request 物件是讀取瀏覽器的資料,通常包含了 
    使用者端的相關訊息,如瀏覽器的種類、表頭資訊、
     *
    表單參數及 Cookies....等,Request物件提供下列資料集合。
    名稱
    說明
    Request.Form("變數名稱") 取得客戶端利用表單所傳送
    的資料
    Request.QueryString
    ("變數名稱")
    取得附帶在網址後面的參數
    Request.Cookies("變數名稱") 取得存在於客戶端瀏覽器
    的Cookies資料
    Request.ServerVariables
    ("變數名稱")
    取得網頁伺服端的環境
    變數資訊
     *本單元將針對 Request.Form("變數名稱")  
    作介紹,其它部分將 Cookies 物件及 Server 
    *
    *以簡單訪客留言為例 製作一表單,程式碼如下:(message.htm)
    *

    *
    1. <form> 標籤的 action (動作)屬性值
    2. 設定為 『go.asp』代表我們按下 
    3. 『傳送』 按鈕後,將由伺服端的 
    4. 『go.asp』接收由此網頁所傳出 
    5. 的網頁資料並加以處理。
    1. <form> 標籤的 method (傳輸方式) 
    2. 屬性值設定為『post』代表我們按下 
    3. 『傳送』按鈕後,瀏覽器將不會立即 
    4. 主動的將資料傳給伺服器,而會等候 
    5. 伺服端來讀取資料並加以處理。另一 
    6. 種method (傳輸方式)屬性值設定為 
    7. 『get』代表我們按下『傳送』按鈕後,
    8. 瀏覽器將會立即主動的將資料傳給 
    9. 伺服器,使用這種方式並不太好! 
    10. 因為當我們按下『傳送』按鈕後,
    11. 表單中的資料將會附在網址之後 
    12. 傳送到伺服器      **
    *
    執行結果如下:
    *
    **
    **
    1. 文字輸入欄位<input>『type』 屬性為 
    2. 輸入欄位的類型,其文字欄位設定值有 
    3. 三種,分別為:『Text』文字輸入欄位 
    4. (只能輸入單行文字)、『Password』保密 
    5. 輸入欄位(單行文字輸入,輸入的文字將 
    6. 以星字號代替)、『Textarea』文字輸入 
    7. 區塊(可輸入多行文字)。
    8. 文字輸入欄位<input>『size』 屬性為 
    9. 文字輸入欄位的寬度  **
    *****************************************

    *按下傳送鈕後會啟動Server端之ASP程式,
    即原始碼中之action="go.asp" ,以下
    為go.asp程式碼:
    1. 利用 request 物件取回 message.htm 網頁中 
    2. 資料輸出識別名稱為欄位資料,並將其 
    3. 資料放置到『name』 的變數中。
    4. 利用 request 物件取回 message.htm 網頁中 
    5. 資料輸出識別名稱為『email』 的欄位資料,
    6. 並將其資料放置到『email』 的變數中。
    7. 利用 request 物件取回 message.htm 網頁中 
    8. 資料輸出識別名稱為『memo』 的欄位資料,
    9. 並將其資料放置到『memo』 的變數中***
    1. 文字輸入欄位<input>『name』 屬性為 
    2. 資料輸出的識別名稱。
    3. 文字輸入欄位<input>『cols』 屬性與 
    4. 『rows』屬性分別為設定『Textarea』文字 
    5. 輸入區塊的欄位數及行數。
    6. 若將『type』 屬性值設為『submit』, 
    7. 則代表此一欄位為一按鈕(Button),按下 
    8. 此按鈕則可將表單中的資料送出,
    9. 『value』 屬性值適用來設定按鈕 
    10. 的標題文字(Caption) ***
    * *
    *注意:<%=顯示內容%><%response.write "
    顯示內容"%>  的簡便寫法    !!*
    *執行結果如下:       *
    * **
    物件單元中介紹    *註:若單純只有取得表單之變數名稱,則 
    Request.Form("變數名稱"), 亦可寫成  
     Request("變數名稱")       *

    ********************************************

    *ASP的輸入  *&*Request物件*
    *Request 物件 :Request 物件與Response 物件是一對的的,
    為何如此說呢?因為Response 物件是回應
    資料給瀏覽器,而Request 物件是讀取瀏覽
    器的資料,通常包含了使用者端的相關訊息,
    如瀏覽器的種類、表頭資訊、表單參數及  
     Cookies....等,Request物件提供下列資料集合 ***
    *
    名稱
    說明
    Request.Form("變數名稱") 取得客戶端利用表單所
    傳送的資料
    Request.QueryString
    ("變數名稱")
    取得附帶在網址後面的參數
    Request.Cookies("變數名稱") 取得存在於客戶端瀏覽器
    的Cookies資料
    Request.ServerVariables
    ("變數名稱")
    取得網頁伺服端的
    環境變數資訊
    *
    *本單元將針對 Request.Form("變數名稱") 
    作介紹,其它部分將 Cookies 物件及 Server
     物件單元中介紹。註:若單純只有取得表單之變數名稱,
    則 Request.Form("變數名稱"), 亦可寫成  
    Request("變數名稱")。  ***
    *以簡單訪客留言為例 製作一表單,
    程式碼如下:(message.htm)              *
    * **
    *
    1. <form> 標籤的 action (動作)屬性值設定 
    2. 『go.asp』代表我們按下『傳送』按鈕後,
    3. 將由伺服端的『go.asp』接收由此網頁所
    4. 傳出的網頁資料並加以處理。
    5. <form> 標籤的 method (傳輸方式)屬性值設 
    6. 定為『post』代表我們按下『傳送』按鈕後
    7. ,瀏覽器將不會立即主動的將資料傳給 
    8. 伺服器,而會等候伺服端來讀取資料並加以 
    9. 處理。另一種method (傳輸方式)屬性值設定 
    10. 『get』代表我們按下『傳送』按鈕後, 
    11. 瀏覽器將會立即主動的將資料傳給伺服器,
    12. 使用這種方式並不太好!因為當我們按下 
    13. 『傳送』按鈕後,表單中的資料將會附 
    14. 在網址 之後傳送到伺服器  ***
    *
    1. 文字輸入欄位<input>『type』 屬性
    2. 為輸入欄位的類型,其文字欄位設定值 
    3. 有三種,分別為:『Text』文字輸入 
    4. 欄位(只能輸入單行文字)、『Password』
    5. 保密輸入欄位(單行文字輸入,輸入的 
    6. 文字將以星字號代替)、Textarea
    7. 文字輸入區塊(可輸入多行文字)。
    8. 文字輸入欄位<input>『size』 屬性為
    9. 文字輸入欄位的寬度。
    10. 文字輸入欄位<input>『name』 屬性 
    11. 為資料輸出的識別名稱。
    12. 文字輸入欄位<input>『cols』 屬性 
    13. 『rows』屬性分別為設定『Textarea』
    14. 文字輸入區塊的欄位數及行數。
    15. 若將『type』 屬性值設為『submit』
    16. 則代表此一欄位為一按鈕(Button),按下 
    17. 此按鈕則可將表單中的資料送出,其 
    18. 『value』 屬性值適用來設定按鈕的 
    19. 標題文字(Caption)   ***
    執行結果如下      *
    **











    ***按下傳送鈕後會啟動Server端之ASP程式,
    即原始碼中之action="go.asp" ,以下
    為go.asp程式碼:
    1. 利用 request 物件取回 message.htm 網頁
    2. 資料輸出識別名稱為欄位資料,並將
    3. 其資料放置到『name』 的變數中。
    4. 利用 request 物件取回 message.htm 網頁
    5. 資料輸出識別名稱為『email』 的欄位
    6. 資料,並將其資料放置到『email』
    7. 變數中。
    8. 利用 request 物件取回 message.htm 網頁
    9. 資料輸出識別名稱為『memo』 的欄位
    10. 資料,並將其資料放置到『memo』 的 
    11. 變數中。
    注意:<%=顯示內容%><%response.write
    "顯示內容"%>  的簡便寫法!
    執行結果如下:
    **
    ****************************************
     
    *ASP的變數紀錄*&*Application物件 *

    *
    *Application 物件*
    *Application 物件是用來管理整個應用程式,
    可提供給客戶端使用者 共享資訊,在實務上
    會被用來追蹤目前使用中的人數及針對特定
    使用者顯示特定資料    *
    *利用Application 物件來記錄變數內容,則網
    頁結束執行時其變數內容仍可保留,也就是
    說Application 物件是一個『靜態』變數,
    如下所示:( App01.asp)            *

    *

    *







    *執行結果如下:         **
    *

    ************************************************
    *Application 物件為『共用資訊』,在不同瀏覽器執行或按重新 
    整理時 ,其值是累加的,例如我們重新執行App01.asp 網頁,
    我們可以清楚的發現:var 變數內的值仍然為上一 
    次執行後保留下來的執行結果: 
    **

    **Application 物件的生命週期 起始於 PWS/IIS 開始運作且有人開始連線時。
     終止於 PWS/IIS 關閉或一定時間內
    (預設為20分鐘)沒人連線時。 也就 
    是說 Application 物件並不是永遠存在的!
    除非我們將 Application 物件中的資料
    寫錄到檔案中將其保存起來,在後續
    的單元中,我們將會特別介紹檔案 
    資料的寫錄與讀取**
    **

    *雖然 Application 物件可以在網頁
    結束後,將其物件內的資料保留下來,
    但是,當有兩位甚至兩位以上的
    瀏覽者同時進行網頁鍊結時,
    則它們所獲得的資料值將是相同的,
    進而使我們統計的資料產生錯誤;
    為了避免兩位甚至兩位以上的瀏覽者
    同時進行網頁鍊結時造成ASP程式
    執行錯誤,可以利用Application 
    物件的操作方法: Application.Lock 
     物件上鎖 與Application.Unlock 取消
    物件上鎖 ,如下所示:(lock.asp)
    如此可避免兩位瀏覽者同時瀏覽
    網頁時,count值加總少加。 即程式
    執行至『Application.lock』程式敘述後,
    就把 Application 物件上鎖,如此一來
    Application 物件便不能被其他程式
    連線者所呼叫使用,須等到呼叫
    『Application.lock』的程式連線者
    再次呼叫了『Application.unlock』取消
    Application 物件上鎖後,其它程式
    連線者才可呼叫 Application***
    ********************************************

    *ASP的變數紀錄*&*Session物件*
    *Session 物件*
    *Session 物件為紀錄使用者的相關
    資訊,提供使用者再次對此網頁
    伺服器要求時作確認,例如使用者
    帳號與密碼的確認,有 Session 物件
    的建立,來保留身分認證的結果,
    則使用者不用於每一頁網頁 登錄
    時都需輸入密碼作確認**
    *Session 物件與 Application 物件相同,
    都是用來記錄『變數』值的,
    但是 Application 是一對多的;
    Session 物件則是一對一的,對於所有
    的連線瀏覽者而言,他們對於 
    Application 物件的使用是『共用』的,
    但是每個瀏覽連線者卻個別擁有一個
    『私用』的 Session 物件,若將
    上節 app01.asp 例子中之內容 
    application 改以 session替代,
    如下所示:(sess01.asp)***
    **
    *


    執行結果同 app01.asp 
    雖然在表面上看來,結果是相同的,
    但是,Session 物件現在紀錄的變數
    資料只與目前瀏覽連線者有關,與其他
    的瀏覽連線者一點關係都沒有,也就是說
    目前所讀取的 Session 物件內容是讀取
    目前瀏覽連線者『私用』的 Session 物件  **
    *Session 物件與 Application物件之
    不同點 :Application物件為共用之資訊,
    而Session卻是個別獨立 的,比較
    下兩圖,不同瀏覽器執行sess01.asp,
    其值是不累加的,由此更可證明:
    Session 物件紀錄的變數資料只與目前
    瀏覽連線者有關,與其他的瀏覽
    連線者一點關係都沒有  **
    ************************
    *Session 物件的生命週期 起始於 
     PWS/IIS 瀏覽器第一次與伺服器
    連線時。 終止於 PWS/IIS 瀏覽器
    結束執行時或瀏覽器一段時間沒有
    向PWS/ IIS要求任何網頁時   **
    *
    1. 當我們利用 Application 來作為進站人數的
    2. 計數器,是利用當有新的瀏覽連線者進入
    3. 時就呼叫 Application 物件,將 Application 
    4.  物件所儲存的變數資料值加一來達到計數
    5. 的目的,但是,上網者只要按下瀏覽器上的
    6. 『重新整理』按鈕後,你會發現計數器將
    7. 會再次的自動加一,這似乎不是我們想要的。
    8. 單純的 Application 計數器程式碼與執行結果,
    9. 如下所列:
    <%
    Application.Lock
    Application("counter") = Application("counter") + 1
    Application.UnLock
    %>

    <HTML>
    <BODY>
    <CENTER><H2>Application計數器<HR></H2>
    進站人數 <%=Application("counter")%> 位
    </BODY>
    </HTML>


    1. 那我們該如何防制連線者按下『重新整理』
    2. 按鈕使計數器自動加一所產生的錯誤呢?
    3. 我們可以利用具有『私用』特性的 Session 
    4. 物件來判斷瀏覽連線者是否是新的連線者,
    5. 我們可以利用下列判斷式先檢驗一下,
    6. 如果是新的連線者,則其Session物件
    7. 是沒有任何資料的!If IsEmpty (Session("Conn")) Then 如果上列的判斷式是成立的(瀏覽連線者為
    8. 新連線的,Session物件內沒有任何的資料),
    9. 則我們就將Application 物件的紀錄資料加一
    10. ,同時將瀏覽連線者的Session("Conn")資料
    11. 值設為『True』,如此一來,當瀏覽連線者
    12. 再次按下『重新整理』按鈕後,
    13. 因為f IsEmpty (Session("Conn")) Then判斷式
    14. 不成立(Session物件內已有連線
    15. 紀錄的資料),則Application 物件的
    16. 紀錄資料就不會再自動加一。使用 
    17. Application 物件與 Session 物件撰寫的
    18. 計數器程式碼與執行結果,如下所列:
    <%
    If IsEmpty(Session("Conn")) Then
    Application.Lock
    Application("counter") = Application("counter") + 1
    Application.UnLock
    End If
    Session("Conn") = True
    %>

    <HTML>
    <BODY>
    <CENTER><H2>Session計數器<HR></H2>
    進站人數 <%=Application("counter")%> 位
    </BODY>
    </HTML>
    *************************************************

    *ASP的變數紀錄*&*Cookies物件*
    (Cookies 物件*
    *

    Application 物件與 Session 物件將資訊
    1. 記錄在 Server端,而 Cookies物件會
    2. 藉由瀏覽器所提供之Cookies功能,
    3. 將資訊記錄在客戶端,也就是說:
    4. Cookies 物件是儲存在瀏覽連線
    5. 者的瀏覽器之中!
    6. 我們可用 Cookies 物件的紀錄來判斷
    7. 某個使用者是否曾經進入本網站。
    8. 奇怪!雖然Session 物件將資訊記錄
    9. 在 Server端,但是它也會個別紀錄連線
    10. 瀏覽者是否曾經進入本網站啊!
    11. 但是Session 物件的生存期限是很短的,
    12. 當瀏覽連線者的瀏覽器在設定時間內
    13. (預設為20分鐘)沒有向伺服器要求
    14. 任何資料的話,伺服器就會將Session 
    15.  物件中的資料全數消除,而 Cookies
    16. 物件是存在於瀏覽連線者的瀏覽器中的,
    17. 即使是瀏覽者離線了,Cookies 物件
    18. 的資料記錄依然存在!
    19.   Cookies 物件是 Response 物件及 
    20. Request 物件之屬性,用法如下: 
      Response.cookies
      寫入Cookies Request.cookies 讀取Cookies ***
    *如何證明 Cookies 物件是儲存在瀏覽 
    連線者的瀏覽器之中?
    1.  將撰寫一含有 Cookies 的網頁, 如下所示 :(Cookies01.asp) *
    **
    *執行後會產生『型態不符合』的錯誤,如下圖:  *
    **
    *
    1. 怎會如此呢?原因如下: Application物件
    2. 及Session物件其傳回值為empty而 
    3.  request.cookies卻是傳回 "" (空字串),
    4. empty可與數 值作運算,"" 卻不可以,
    5. 解決此一問可加入一判斷式, 如下所示:
    if var="" then var=empty
    ' 如果var="",則將var設定成empty


    修改後還是有錯誤,錯誤為『已將HTTP標題
    寫入用戶端瀏覽器。 對任何HTTP的標題所
    做的修改必須要在寫入頁內容之前』。


    1. 原因 為瀏覽器與伺服端交換 Cookies資料
    2. 的時機需在伺服器尚未下載 資料給瀏覽器
    3. 之前就進行交換,否則會出現錯誤,解決
    4. 方法為用 緩衝區來裝下載的資料,
    5. 完整程式如下所示:


    1. 現在我們來檢驗一下:以IE 為例,建立
    2. 在瀏覽器中的 Cookies 物件將會放置在 『\WINDOWS\Temporary Internet Files』
    3. 目錄中,我們先將目錄中的所有資料
    4. 檔案清除乾淨:
    接著啟動瀏覽器,開始瀏覽 cookies02.asp ,
    此時我們將會發現在 
    『\WINDOWS\Temporary Internet Files』
    目錄中多出了Cookies 的物件檔案,
    這證明了Cookies 物件是存在於瀏覽連線者 
    的瀏覽器(客戶端)中無誤!


    Cookies 物件的生命週期起始於瀏覽器
    被執行時。終止於瀏覽器結束執行時。
    那如果我們要延長Cookies 物件的生命週期呢?
    若要延長Cookies 物件的生命週期我們可另用
    『Expires』屬性來設定Cookies的生命週期,
    Expires表失效 ,如下所示 :
    response.cookies("yourID")="cookies"
    response.cookies("yourID").expires="2000/12/31/"
      經過expires設定後,yourID之使用 
    期限為2000/12/31*((^^
    **********************************************

    *伺服器資訊*&*Server物件 *
    *Server 物件 Server 物件允許使用者取得伺服器提供的 
    各項功能,本單元將介紹 Request 物件的
    ServerVariables方法及Server物件 ***
    *Request.ServerVariables 方法:利用此
    方法可取得伺服器提供的各項功能,
    其敘述如下  :
       Request.ServerVariables("環境變數") 
    環境變數有很多,在此將只介紹較實用的,
    其他環境變數可參考 PWS/IIS提供之參考文件。 
    1. 讀取IP位址的環境變數 "LOCAL_ADDR"serverID=request.servervariables("LOCAL_ADDR") 
    2.  讀取Server端的IP位址 
    3. "REEMOTE_ADDR" 讀取Client端的IP位址 clientID=request.servervariables("REMOTE_ADDR") 
    4. 讀取附帶在網址後面的參數  
    5.  "QUERY_STRING"  element=request.servervariables("QUERY_STRING") 亦可以下列方法替代,其結果是相同的。 element=request.querystring 假設所輸入的網址為 http://127.0.0.1/asp/ch01/elemenet.asp? name=kelvin&interest=play 則變數element="name=kelvin&interest=play" 我們可藉由split函
    6. 數解析element變數,如下所示:(element.asp)
     

    Server 物件
    1.  Server.MapPath:將網址路徑轉為真實的檔案
    2. 路徑 因為ASP規定必須指定檔案的真實
    3. 路徑,用法如下: 
    真實的路徑=Server.MapPath("虛擬路徑")
    什麼叫做『虛擬路徑』?虛擬路徑其實就是
    『網址』,當我們連結至某個網站的根目錄時,
    我們就會在瀏覽器的網址輸入欄位中輸入網站
    的網址,例如:http://www.twYYY.com/,這就 
    表示我們要鍊結至該網站的根目錄,但是實際
    對應到該網站伺服器上硬碟根目錄卻是  『\Inetpub\wwwroot』,所以,說穿了
    『網址』就是『假』的網站伺服器目錄,
    只不過『假』很不好聽,因此我們就
    稱之為『虛擬』!
    如果我們所安裝的 PWS/IIS 網路伺服器模擬
    機制的 www 根目錄(網址虛擬根目錄)為  『c:\Inetpub\wwwroot』,我們若使用 
    Server.MapPath("/")呼叫敘述,則回傳的資料值將是  『c:\Inetpub\wwwroot』;我們若使用
    Server.MapPath("/test")呼叫敘述,則回傳的資料值將是  『c:\Inetpub\wwwroot\test』。
    為何需轉換『虛擬路徑』為真實的路徑呢?
    因為當我們需要開啟檔案或是資料庫時,
    ASP 強硬的規定我們必須指定欲開啟檔案 
    (或資料庫)的『實際路徑』之故!

    1.  對特殊字元進行編碼 "HTMLEncode"
    如果我們要在網頁中單純的顯示
    <b>粗體</b>』這些單純的文字時,
    該如何編寫我們的ASP網頁呢?如果我們
    撰寫的敘述如下圖a所編寫的內容一般,
    則以瀏覽器瀏覽網頁時將會獲得如圖b的 
    錯誤答案:
    怎麼會這樣呢?因為<b></b>輸出至
    瀏覽器後都會被解譯為 HTML 網頁標籤了!
    那怎麼辦啊!這個時候我們就必須利用
    Server.HTMLEncode 來進行字元編碼,
    其標準格式為:
    Server.HTMLEncode ("要進行編碼的資料")
    以剛剛要被單純輸出的資料為例:
    Server.HTMLEncode ("<b>粗體</b>"),經過編碼之後
    所得的答案將是『&lt;b&gt;粗體&lt;/b&gt;』,
    如此一來,當瀏覽器對網頁內容進行解譯時,
    這些經過編碼過的資料瀏覽器就只會將它們
    解碼回原來的特殊字元而不會解譯為 HTML
    網頁標籤了!
    執行結果:
    *
    *********************************************

    *檔案存取~~**
    物件(上)*
    *File Access 元件  *
    *File Access 元件允許ASP程式存取網頁伺服器 
    上的檔案,實務上大 部份以文字檔為主,
    事實上,File Access元件是由FileSystemObject 
     物件及TextStream 物件所組成的。
     FileSystemObject 物件負責開啟檔案或是目錄
    的處裡,但若想讀取 檔案內容,則必須配合
    TextStream 物件一起使用。 File Access元件已
    包含在IIS4.0中,因此,不需重新安裝此元件
    就可直接使用。 語法如下所示   : 
    set fs=CreateObject("Scripting.FileSystemObject") *

    *FileSystemObject 物件
    建立FileSystemObject 
    ,程式如下:

     檔案操作的方法: 
    CopyFile 複製檔案,語法如下: 
    FileSystemObject.copyfile source,
    destination[,overwrite] 
    1. source(來源檔案):必須是已存在的檔案,
    2. 否則會產生『找不到來 源檔案』的錯誤
    3. (err.numer=53)。
    4. destination(目的檔案):檔案若已存在,
    5. 則會被覆蓋,若為唯讀屬 性或被鎖定的
    6. 檔案,則會產生『沒有使用權限』的錯誤  (err .number=70)。 
    7. overwrite(是否覆蓋):預設值為true,表示存
    8. 在的檔案將被覆蓋。
    9.  範例程式碼如下    :
     

    DeleteFile:刪除檔案,語法如下 
    FileSystemObject.Deletefile Filename[,Flag]  
    1. Filename(被刪除的檔案):必須為已存在的
    2. 檔案,否則會產生『找 不到來源檔』的錯誤(err.number=53)。 
    3. Flag(true or false):預設值為false,true表可
    4. 以刪除唯讀屬性 設定的檔案,若不設為 true,
    5. 則遇到唯讀屬性檔案時將產 生『沒有使用權限』
    6. 的錯誤 (err.number=70)。
    7. 範例程式碼如下   :

    MoveFile 移動檔案或更名,語法如下: 
    FileSystemObject.Movefile source,destination 
    1. Source(來源檔案):必須是已存在的檔案,
    2. 否則會產生『找不到來 源檔』的錯誤
    3. (err.numer=53)。
    4.  Destination(目的檔案):必須是不存在的檔案,
    5. 否則會產生『 檔 案已存在』的錯誤
    6. (err.number=58)。
    7. 若source與destination 所在目錄相同,
    8. 則 MoveFile之 功用是更名,若 source與  
    9. destination所在目錄不同,則MoveFile之
    10. 功用是移動檔案。 範例程式碼如下  :

     
    FileExists 檔案是否存在,語法如下:
      FileSystemObject.FileExists(Filename)  
    檔案若存在,則傳回值為true,否則傳回false  *

    ***File Access物件(下) *
    *TextStream 物件
     TextStream 物件為FileSystemObject 物件的

    子物件,建立的方法有兩種  *
    *OpenTextFile 開啟檔案 
    set fs=server.CreateObject("Scripting.FileSystemObject")
    set txt=fs.OpenTextFile(參數...)
     
    OpenTextFile所傳的參數如下: 
    OpenTextFile(Filename[,IOmode[,Create]]) 
    Filename(檔案名稱)、 IOmode(開啟模式):可以
    有下列三種設定值
    設定值說明
    1 開啟成為讀的檔案預設值為1
    2開啟成唯寫的檔案原檔案內容會被清除
    8開啟成唯寫的檔案原檔案內如保留資料會
    從檔案最後面寫入


    Create(是否自動建檔):預設為false,表開啟的
    檔案必須是已經 存在的檔案,若設成true,
    則當所要開啟的檔案不存在時 ,
    FileSystemObject會自動建立檔案。
    其中IOmode與Create參數可省略。

    CreateTextFile 建立新檔案
    set fs=server.CreateObject("Scripting.FileSystemObject")
    set txt=fs.CreateTextFile(參數...)
     
    CreateTextFile所傳的參數如下: 
    CreateTextFile(Filename[,Overwrite])  
    OverWrite(是否覆寫原檔案):需建立在檔案
    已存在的情況下,此 參數才有效。若設為 
    true(預設),則原檔案會被覆寫,若 設為false,
    則會出現『檔案已存在』的錯誤。

     讀取檔案的方法 
    1. ReadLine:從檔案中讀取一行資料,如下例:
     
    1. Read(N):從檔案中讀取N個位元組的資料,
    2. 如下例:
     
    1. ReadAll:讀取檔案中的所有資料,如下例:


     
    寫入檔案的方法 

    1. WriteLine:會在資料後加vbCrLf,才將資料
    2. 寫到檔案中。
    3. Write:原原本本將資料寫入檔案中,如下例:



    ***********************THE END*********************