markdown W3Cx的Game / EdX JavaScript入门课程/

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了markdown W3Cx的Game / EdX JavaScript入门课程/相关的知识,希望对你有一定的参考价值。

#myCanvas {
    border: 1px solid black;
    z-index: 1;
    position: relative;
    left: 50%;
    transform: translateX(-50%);
}

input {
    z-index: 2;
}

html, body {
    width: 100%;
}

.container {
    width: 100%;
}

.row {
    width: 100%;
    height: auto;
}

.row::after {
    content: "";
    clear: both;
    display: table;
}

[class*="col-"] {
    width: 100%;
}

@media only screen and (min-width: 768px) {
    .col-1-2 {
        width: 50%;
        height: 100%;
        float: left;
    }
}

/**************TABLE***********/

table, form {
    position: absolute;
    left: 50%;
    /* top: 50%; */
    transform: translateX(-50%);
    z-index: 1000;
    margin-top: 80px;
}

caption, th {
    padding: 20px;
}

td {
    padding: 10px;
}

caption {
    background-color: #ffff00;
    font-weight: bold;
}

table, tr, th, td {
    border: 1px solid #ffffff;
    border-collapse: collapse;
}

th {
    background-color:#99ff33;
}

td {
    text-align: center;
}

#table tr:nth-child(even){
    background-color: #f2f2f2;
}

#table tr:hover {
    background-color: #ddd;
}

var canvas, ctx, w, h;

var bullets = [];

var balls = [];
var numberOfBalls = 10;
var index = 0;
var numberOfGoodBalls = 0;
var goodBallsEaten = 0;
var wrongBallsEaten = 0;
var colorToEat = "red";
var oneBallColorToEateCreated = false;
var gameOver = false;
var newLevel = false;
var level = 1;
var speedCoef = 1;
var requestId;

var nowPlayingIndex = 14;
var gameBackgroundIndex;
var newBackground = false;

var mousePosition;

var currentScore = 0;

var numberOfAssetsToLoad = 0;

var player = {
    width: 20,
    height: 20,
    x: 10,
    y: 10,
    color: "red",

    move: function(x, y) {
        if(mousePosition !== undefined){
            this.x = x;
            this.y = y;
        }
    },

    draw: function() {
        drawFilledRect(this)
    }
}


var assetsToLoadURLs = {
    backgroundImage: { url: 'https://mainline.i3s.unice.fr/mooc/SkywardBound/assets/images/background.png' }, // http://www.clipartlord.com/category/weather-clip-art/winter-clip-art/
    backgroundImage1: { url: 'http://www.clker.com/cliparts/0/b/0/f/1197119063962204382ryanlerch_grassy_horizon_(gradient).svg.hi.png' },
    backgroundImage2: { url: 'http://www.clker.com/cliparts/c/0/1/d/12065578651282111944chelseafan528_Grassy_Scene.svg.hi.png' },
    backgroundImage3: { url: 'http://www.clker.com/cliparts/d/8/0/4/12074334211624055201rygle_Creation_Scene_3.svg.hi.png'},
    backgroundImage4: { url: 'http://www.clker.com/cliparts/1/3/4/a/1237098635915429223StudioFibonacci_Cartoon_Hillside_with_Butterfly_and_Flowers.svg.hi.png'},
    backgroundImage5: { url: 'http://www.clker.com/cliparts/9/d/c/a/1234405664842624179rg1024_grass.svg.hi.png'},
    backgroundImage6: { url: 'http://www.clker.com/cliparts/8/6/5/a/1240172473914282518StudioFibonacci_Cartoon_spring.svg.hi.png'},
    backgroundImage7: { url: 'http://www.clker.com/cliparts/Z/4/l/A/S/L/background-hi.png'},
    logo1: { url: "https://mainline.i3s.unice.fr/mooc/SkywardBound/assets/images/SkywardWithoutBalls.png" },
    logo2: { url: "https://mainline.i3s.unice.fr/mooc/SkywardBound/assets/images/BoundsWithoutBalls.png" },
    bell: { url: "https://mainline.i3s.unice.fr/mooc/SkywardBound/assets/images/bells.png" },
    spriteSheetBunny: { url: 'https://mainline.i3s.unice.fr/mooc/SkywardBound/assets/images/bunnySpriteSheet.png' },
    humbug: { url: 'https://mainline.i3s.unice.fr/mooc/SkywardBound/assets/sounds/humbug.mp3', buffer: true, loop: true, volume: 1.0 },
    concertino: { url: 'https://mainline.i3s.unice.fr/mooc/SkywardBound/assets/sounds/christmas_concertino.mp3', buffer: true, loop: true, volume: 1.0 },
    xmas: { url: 'https://mainline.i3s.unice.fr/mooc/SkywardBound/assets/sounds/xmas.mp3', buffer: true, loop: true, volume: 0.6 },
    helperSound    : {url: "https://mainline.i3s.unice.fr/mooc/StarWarriors/assets/0B_E4HKbPQZo6MFBDb3JsVFRxN1E.mp3", buffer: false, loop: false, volume: 1.0,  type:"sound"},
    bombsFly       : {url: "https://mainline.i3s.unice.fr/mooc/StarWarriors/assets/0B_E4HKbPQZo6OEFZYzZ3ajNEUVk.mp3", buffer: false, loop: false, volume: 1.0, type:"sound"},
    clickCosmos    : {url: "https://mainline.i3s.unice.fr/mooc/StarWarriors/assets/0B_E4HKbPQZo6MDFPaFkwdjJSY3M.mp3", buffer: false, loop: false, volume: 1.0, type:"sound"},
    clickMenu      : {url: "https://mainline.i3s.unice.fr/mooc/StarWarriors/assets/0B_E4HKbPQZo6WTltOXBVaE5vb1E.mp3", buffer: false, loop: false, volume: 1.0, type:"sound"},
    littleClick    : {url: "https://mainline.i3s.unice.fr/mooc/StarWarriors/assets/0B_E4HKbPQZo6TVROZWxfenIzMUE.mp3", buffer: false, loop: false, volume: 1.0, type:"sound"},
    strangerHit    : {url: "https://mainline.i3s.unice.fr/mooc/StarWarriors/assets/0B_E4HKbPQZo6WDBhMzJrM29fYXc.mp3", buffer: false, loop: false, volume: 1.0, type:"sound"},
    tuk            : {url: "https://mainline.i3s.unice.fr/mooc/StarWarriors/assets/0B_E4HKbPQZo6Y0ZYbHZYeU1CNnM.mp3", buffer: false, loop: false, volume: 1.0, type:"sound"},
    tukLouder      : {url: "https://mainline.i3s.unice.fr/mooc/StarWarriors/assets/0B_E4HKbPQZo6TTRmQ2c0QjBEb1E.mp3", buffer: false, loop: false, volume: 1.0, type:"sound"},
    fire           : {url: "https://mainline.i3s.unice.fr/mooc/StarWarriors/assets/0B_E4HKbPQZo6blZhMV9FSTl4UHM.mp3", buffer: false, loop: false, volume: 1.0, type:"sound"},
    soundCrash     : {url: "https://mainline.i3s.unice.fr/mooc/StarWarriors/assets/0B_E4HKbPQZo6X1RLSE9qTGxwYWM.mp3", buffer: false, loop: false, volume: 1.0, type:"sound"},
    rocketHit      : {url: "https://mainline.i3s.unice.fr/mooc/StarWarriors/assets/0B_E4HKbPQZo6SGpyMDlRYzhydnM.mp3", buffer: false, loop: false, volume: 1.0, type:"sound"},
    plop: { url: 'https://mainline.i3s.unice.fr/mooc/SkywardBound/assets/sounds/plop.mp3', buffer: false, loop: false, volume: 1.0 },  
};

var loadedAssets;



window.onload = function init(){

    canvas = document.querySelector("#myCanvas");
    ctx = canvas.getContext('2d');
    w = canvas.width;
    h = canvas.height;
    canvas.addEventListener('mousemove', mouseMoved);
    window.addEventListener('keydown', createBullet);

    balls = createAllBalls(numberOfBalls);
    numberOfGoodBalls = countNumberOfGoodBalls(balls, colorToEat);
   
    loadAssets(startGame);
}

class Ball {
    constructor(color) {
        this.x = w/2;
        this.y = h/2;
        this.radius = 5 + 30 * Math.random(); // between 5 and 35
        this.speedX = -5 + 10 * Math.random(); // between -5 and + 5
        this.speedY = -5 + 10 * Math.random(); // between -5 and + 5
        if(!color){
         this.color = getRandomColor();   
        } 
        else {
         this.color = color;   
        }
        
    }

    draw(){
        ctx.save();
        ctx.fillStyle = this.color;
        ctx.translate(this.x, this.y);
        ctx.beginPath();
        ctx.arc(0,0,this.radius,0,2*Math.PI);
        ctx.fill();
        ctx.restore();
        index = balls.indexOf(this);
        testCollisionWithBullets(this, index);
    }

    move(){
        this.x += (this.speedX * speedCoef);
        this.y += (this.speedY * speedCoef);
        testColisionWithWalls(this);
    }
}

class Bullet {
    constructor(){
        this.width = 5;
        this.height = 5;
        this.color = "blue";
        this.x = player.x + player.width/2 - 5/2;
        this.y = player.y;
    }
    
    draw(){
        if(bullets.length !== 0)
        drawFilledRect(this);
    }
        
    move(){
        if(bullets.length !== 0)
        this.y -= 5;
    }
}


function startGame(assetsReadyToBeUsed) {
    //document.body.innerHTML += "<p>IMAGES, SOUNDS, MUSICS READY TO BE USED!</p>";
    // We're ready to use all sounds, images, musics etc
    loadedAssets = assetsReadyToBeUsed;
    firstStart();
}

function firstStart(){
    ctx.clearRect(0,0,w,h);
    drawBackground();
    ctx.save();
    ctx.font = "20px Arial";
    ctx.fillText("Press a key to start! Press space to fire!", 20, 70);
    ctx.restore();
    window.addEventListener('keydown', firstStartGame);   
}

function firstStartGame(){
    window.removeEventListener('keydown', firstStartGame);
    loadedAssets[nowPlayingIndex].play();
    mainLoop();
}

function chooseBackgroundIndex(){
    var i = Math.floor(Math.random() * 8);
    gameBackgroundIndex = i;
}

function playBackgroundMusic(){
    loadedAssets[nowPlayingIndex].stop();
    var i = Math.floor(Math.random() * (14 - 12 + 1)) + 12;
    loadedAssets[i].play();
    nowPlayingIndex = i;
}
  

function countNumberOfGoodBalls(balls, colorToEat) {
    var nb = 0;
    
    balls.forEach(function(b) {
      if(b.color === colorToEat)
        nb++;
    });
    
    return nb;
}

function createAllBalls(nb){
    var arr = [];
    var ballWithColorToEat = new Ball(colorToEat); //Create at least one ball with color to eat;
    arr.push(ballWithColorToEat);
    for (i = 1; i < nb; i++){
        var b = new Ball();
        arr.push(b);
    }
    return arr;
}

function getRandomColor(){
    if(oneBallColorToEateCreated) {
    var colors = ['red','blue','green','yellow'];
    var index = Math.round(Math.random()*(colors.length-1));
    var colorChoosen = colors[index];
    }
    else {
        colorChoosen = colorToEat;
        oneBallColorToEateCreated = true;
    }
    return colorChoosen;
}

function createBullet(event){
    if(event.keyCode === 32){
        var bullet = new Bullet;
        bullets.push(bullet);
    }
}

function mainLoop(){
    if(gameOver || newLevel){
        gameOverMenu();
    }
    else {
    ctx.clearRect(0,0,w,h);
    drawBackground();

    player.draw();
    player.move(mousePosition.x, mousePosition.y);
    

    drawBullets();    
    moveBullets();
    

    drawBalls();
    moveBalls();
  
    drawBallNumbers(balls);
    requestId = window.requestAnimationFrame(mainLoop);
    }
}

function moveBullets(){
    bullets.forEach(function(bullet){
        bullet.move();
    });
}

function drawBullets(){
    bullets.forEach(function(bullet){
        bullet.draw();
    });
}

function drawBalls(){
    balls.forEach(function(ball){
        ball.draw();
    });
}

function moveBalls() {
    balls.forEach(function(ball){
        ball.move();
    });
}


function drawBackground(){
    if(!newBackground){
        chooseBackgroundIndex();
        newBackground = true;
    }
    ctx.drawImage(loadedAssets[gameBackgroundIndex], 0, 0, w, h);
}




function drawBallNumbers(balls) {
    ctx.save();
    ctx.font="20px Arial";
    currentScore = numberOfBalls - wrongBallsEaten;
    if(wrongBallsEaten === 3) {
      ctx.fillText("Game Over! You hit tree wrong balls!", 20, 30);
      gameOver = true;
    } else if(goodBallsEaten === numberOfGoodBalls) {
      ctx.fillText("You Win! Final score : " + currentScore, 
                   20, 30);
                   newLevel = true;
    } else {
      ctx.fillText("Balls still alive: " + balls.length, 210, 30);
      ctx.fillText("Good Balls eaten: " + goodBallsEaten, 210, 50);
      ctx.fillText("Wrong Balls eaten: " + wrongBallsEaten, 210, 70);
      ctx.fillText("Score: " + currentScore, 210, 90);
    }
    ctx.fillText("Level: " + level, 20, 390)
    ctx.restore();
}

function testColisionWithWalls(b){
    if((b.x + b.radius) > w){
        b.x = w - b.radius;
        b.speedX = - b.speedX;
    }
    else if((b.x - b.radius) < 0){
        b.x = b.radius;
        b.speedX = - b.speedX;
    }
    if((b.y + b.radius) > h){
        b.y = h - b.radius;
        b.speedY = -b.speedY;
    }
    else if((b.y - b.radius) < 0){
        b.y = b.radius;
        b.speedY = -b.speedY;
    }
}

function testCollisionWithBullets(b, index) {
    for(i=0; i < bullets.length; i++){
        if(circRectsOverlap(bullets[i].x, bullets[i].y, 
            bullets[i].width, bullets[i].height,
                       b.x, b.y, b.radius)) {
      // we remove the element located at index
      // from the balls array
      // splice: first parameter = starting index
      //         second parameter = number of elements to remove
        if(b.color === colorToEat) {
        // Yes, we remove it and increment the score
            goodBallsEaten += 1;
        } else {
        wrongBallsEaten += 1;
        }
      
        balls.splice(index, 1);
        loadedAssets[24].play();
  
        }
    }
}

function circRectsOverlap(x0, y0, w0, h0, cx, cy, r) {
    var testX=cx;
    var testY=cy;
    if (testX < x0) testX=x0;
    if (testX > (x0+w0)) testX=(x0+w0);
    if (testY < y0) testY=y0;
    if (testY > (y0+h0)) testY=(y0+h0);
    return (((cx-testX)*(cx-testX)+(cy-testY)*(cy-testY))< r*r);
}


function mouseMoved(evt){
    mousePosition = getMousePos(evt, canvas);
}

function getMousePos(evt, canvas){
    var rect = canvas.getBoundingClientRect();
    return {
        x: (evt.clientX - rect.left),
        y: (evt.clientY - rect.top)
    };
}

function drawFilledRect(r){
    ctx.save();
    ctx.translate(r.x, r.y);
    ctx.fillStyle = r.color;
    ctx.fillRect(0,0,r.width,r.height);
    ctx.restore();
}


function gameOverMenu(){
    playBackgroundMusic();
    ctx.save();
    ctx.font = "20px Arial";
    if (gameOver){
    makeTableHightScore(currentScore);
    //ctx.fillText("Press enter to restart!", 20, 70);
    }
    else {
       // currentScore += (goodBallsEaten - wrongBallsEaten);
        ctx.fillText("Press a key to continue", 20, 70);
        level++;
        numberOfBalls++;
        window.addEventListener('keydown', restart);
    }
    ctx.restore();
}


function gameOverRestart(evt){
    if(evt.keyCode == 13){
        window.removeEventListener('keydown', gameOverRestart);
        document.querySelector("#nbBalls").value = numberOfBalls;
        deleteElement("table");
        restart();
    }
}

function restart(){
    window.removeEventListener('keydown', restart);
    goodBallsEaten = 0;
    wrongBallsEaten = 0;
    balls = createAllBalls(numberOfBalls);
    numberOfGoodBalls = countNumberOfGoodBalls(balls, colorToEat);
    bullets = [];
    gameOver = false;
    newLevel = false;
    playBackgroundMusic();
    newBackground = false;
    mainLoop();
}


function changeNbBalls(n){
    window.cancelAnimationFrame(requestId);
    numberOfBalls = n;
    restart();
}

function changePlayerColor(c){
    player.color = c;
}

function changeColorToEat(c){
    window.cancelAnimationFrame(requestId);
    colorToEat = c;
    restart();
}

function changeBallSpeed(s){
    speedCoef = s;
}



function changeBackgroundSong(value){
    loadedAssets[nowPlayingIndex].stop();
    var i;
    for (var j = 0; j < numberOfAssetsToLoad; j++) {
            if (loadedAssets[j].name == value) {
                i = j;
                loadedAssets[nowPlayingIndex].stop();
                loadedAssets[i].play();
                nowPlayingIndex = i;
                return;
            }
    }
}


function changeSongVolume(v){
    var value = v / 10;
    Howler.volume(value);
}

  
function loadAssets(callback) {
    // here we should load the sounds, the sprite sheets etc.
    // then at the end call the callback function           
    loadAssetsUsingHowlerAndNoXhr(assetsToLoadURLs, callback);
}

// You do not have to understand in details the next parts of the code...
// just use the above function

/* ############################
    BUFFER LOADER for loading multiple files asyncrhonously. The callback functions is called when all
    files have been loaded and decoded 
 ############################## */
function isImage(url) {
    return (url.match(/\.(jpeg|jpg|gif|png)$/) != null);
}

function isAudio(url) {
    return (url.match(/\.(mp3|ogg|wav)$/) != null);
}

function loadAssetsUsingHowlerAndNoXhr(assetsToBeLoaded, callback) {
    var id = 0;
    var assetsLoaded = {};
    var loadedAssets = 0;
   // var numberOfAssetsToLoad = 0;

    // define ifLoad function
    var ifLoad = function () {
        if (++loadedAssets >= numberOfAssetsToLoad) {
            callback(assetsLoaded);
        }
        console.log("Loaded asset " + loadedAssets);
    };

    // get num of assets to load
    for (var name in assetsToBeLoaded) {
        numberOfAssetsToLoad++;
    }

    console.log("Nb assets to load: " + numberOfAssetsToLoad);

    for (name in assetsToBeLoaded) {
        var url = assetsToBeLoaded[name].url;
        console.log("Loading " + url);
        if (isImage(url)) {
            
            //assetsLoaded[name] = new Image();
            //assetsLoaded[name].onload = ifLoad;
            // will start async loading. 
            //assetsLoaded[name].src = url;
            //assetsLoaded[name].id = id;
            assetsLoaded[id] = new Image();
            assetsLoaded[id].onload = ifLoad;
            assetsLoaded[id].name = name;
            assetsLoaded[id].src = url;
            id++;
        } else {
            // We assume the asset is an audio file
            console.log("loading " + name + " buffer : " + assetsToBeLoaded[name].loop);
           // assetsLoaded[name] = new Howl({
              assetsLoaded[id] = new Howl({
                urls: [url],
                buffer: assetsToBeLoaded[name].buffer,
                loop: assetsToBeLoaded[name].loop,
                autoplay: false,
                volume: assetsToBeLoaded[name].volume,
                onload: function () {
                    if (++loadedAssets >= numberOfAssetsToLoad) {
                        callback(assetsLoaded);
                    }
                    console.log("Loaded asset " + loadedAssets);
                }
            }); // End of howler.js callback
            assetsLoaded[id].name = name;
            id++;
        } 

    } 
} 

function makeTableHightScore(currentScore){
    makeFormScoreRegistration();
}

function makeFormScoreRegistration(){
    var form = document.createElement("form");
    form.setAttribute("id", "form");
    form.setAttribute("action", "javascript:void(0);");
    var label = document.createElement("label");
    label.setAttribute("for", "userName");
    var input = document.createElement("input");
    input.setAttribute("id", "userName");
    input.value = "User";
    label.appendChild(input);
    var submit = document.createElement("input");
    submit.setAttribute("type", "submit");
    submit.setAttribute("onclick", "getUserData();");
    label.appendChild(submit);
    form.appendChild(label);
    var tableDiv = document.getElementById("tableContainer");
    tableDiv.appendChild(form);
    //document.body.appendChild(form);
}

function getUserData(){
    SaveScoreIfItIsBestScore();
    currentScore = 0;
    showHighScore();
    
}

function SaveScoreIfItIsBestScore(){
    var userInput = document.getElementById("userName").value;
    var newScore = [];
    var ar = [userInput, currentScore];
    newScore.push(ar);
    if(sessionStorage.length == 0){
        saveCurrentScoreToSessionSt(newScore); 
    }
    else {
        var storage = sessionStorage.getItem("bestScores");
        var arr = JSON.parse(storage);
            if(arr.length < 5){
                arr.push(ar);
            }
            else {
                    if(arr[arr.length-1][1] <= currentScore){
                    arr.pop();
                    arr.push(ar); 
                    }
            } 
        arr.sort(function(a, b) {return a[1] < b[1] ? 1 : -1;});
        saveCurrentScoreToSessionSt(arr);
    }
}

function saveCurrentScoreToSessionSt(arr){
        sessionStorage.clear();
        sessionStorage.setItem("bestScores", JSON.stringify(arr));
        
}

function showHighScore(){
    var storage = sessionStorage.getItem("bestScores");
    var arrayOfUsers = JSON.parse(storage);
    var table = document.createElement("table");
    table.setAttribute("id", "table");
    var caption = table.createCaption().outerHTML = "<caption>High Score</capion>";
    var thead = table.insertRow().outerHTML = "<tr><th>User</th><th>Score</th></tr>";
    for(i=0; i < arrayOfUsers.length; i++){
        var row = table.insertRow();
        var userCell = row.insertCell().innerHTML = arrayOfUsers[i][0];
        var scoreCell = row.insertCell().innerHTML = arrayOfUsers[i][1];
    }
    var tableDiv = document.getElementById("tableContainer");
    tableDiv.appendChild(table); 
    deleteElement("form");

    ctx.save();
    ctx.font = "20px Arial";
    ctx.fillText("Press enter to restart!", 20, 70);
    ctx.restore();
    

    window.addEventListener('keydown', gameOverRestart);
}

function deleteElement(id){
    document.getElementById(id).outerHTML = "";
};

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Draw a monster in a canvas</title>
  <link rel="stylesheet" type="text/css" href="style.css"/>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/howler/1.1.28/howler.min.js"></script>
</head>
<body>
  <div class="container">
    <div class="row">
      <div id="controls" class="col-1-2">
        <label for="nbBalls">Number of balls: </label>
        <input type="number" min=1 max=30 
           value=10 id="nbBalls"
           oninput="changeNbBalls(this.value);">
        <p></p>
        <label for="colorChooser">Player color: </label>
        <input type="color" value='#FF0000' oninput="changePlayerColor(this.value);" id="colorChooser">
        <p></p>
        <label for="selectColorOfBallToEat">Color of ball to eat: </label>
        <select onchange="changeColorToEat(this.value);" id="selectColorOfBallToEat">
          <option value='red'>red</option>
          <option value='blue'>blue</option>
          <option value='green'>green</option>
        </select>
        <p></p>
        <label for="ballSpeed">Change ball speed: </label>
        -&nbsp;<input type="range" value='1' min=0.1 max=3 step=0.1 oninput="changeBallSpeed(this.value);" id="ballSpeed"> 
        +&nbsp;
        <p></p>
      </div>
      <div id="audioControls" class="col-1-2">
        <label for="backgroundSong">Choose backgground song: </label>
        <select id="audioControlsBackgroundSongs" onchange="changeBackgroundSong(this.value)">
          <option value="xmas">Xmas</option>
          <option value="humbug">Humbug</option>
          <option value="concertino">Concertino</option>
        </select>
        <p></p>
        <label for="songVolume">Song volume: </label>
        <input  id="songVolumeRange" type="range" min="0" max="10" value="" onchange="changeSongVolume(this.value)">
      </div>
    </div>
    <div class="row">
      <div id="tableContainer"></div>
      <canvas id="myCanvas"  width="400" height="400">
      </canvas>
    </div>
  </div>
  <script src="script.js"></script>
</body>
</html>
Game  /EdX's JavaScript Introduction Course by W3Cx/
----------------------------------------------------


A [Pen](https://codepen.io/Onlyforbopi/pen/LgPypZ) by [Pan Doul](https://codepen.io/Onlyforbopi) on [CodePen](https://codepen.io).

[License](https://codepen.io/Onlyforbopi/pen/LgPypZ/license).

以上是关于markdown W3Cx的Game / EdX JavaScript入门课程/的主要内容,如果未能解决你的问题,请参考以下文章

html JS.Templates.Contact manager / EdX的W3Cx JavaScript入门课程/

html JS.JSON.Dynamic table / EdX的W3Cx的JavaScript入门课程/

html 来自https://courses.edx.org/courses/course-v1:W3Cx+HTML5.1x+3T2016/courseware/b246c15d3a1044ccb45

css 来自https://courses.edx.org/courses/course-v1:W3Cx+HTML5.1x+3T2016/courseware/b246c15d3a1044ccb456

markdown Edx备忘录

markdown JS.JSON.Study at edX - 显示远程数据