SpaceTraffic: TestPohybPlanet1

from Wiki KIVu

21.1.2011 - Pohybu planet a možnosti vykreslování v JS


Zpět na HomePage


Vykreslování soustavy

Problém původní implementace V.iterace 2009/2010

Původní implementace je hned ve dvou bodech:

Požadavky na novou implementaci

Nová implementace získá od serveru pouze výchozí parametry jednotlivých objektů.

Základ je počáteční poloha (v čase t), parametry dráhy a parametry objektu. Veškeré další vykreslování bude prováděno na straně klineta včetně optimalizací pro klientovo rozlišení.

Dynamické objekty (lodě) budou do vykreslování přidávány za chodu.

Možnosti vykreslování

Základní varianta

Využití css vlastností top a left a jejich nastavení pomocí skriptu. V této variantě není dostupná transformace rotace.

Ukázka pohybu Ukázka pohybu

CSS3? vlastnost transform

Vlastnost transform umožňuje zadat objektu transformační matici pro vykreslení.

Tato vlastnost je podporována ve všech současných prohlížečích kromě IE8?, kde však lze použít vestavěnou funkci pro dosažení stejného efektu.

Výhodou tohoto řešení je především jednoduchost a možnost používat běžné postupy z počítačové grafiky pro výpočty.

Lze doplnit o podporu další grafiky.

Canvas / SVG

Podpora canvas a svg je další možná implementace. Je zde problém s IE, který bude obě technologie podporovat až ve verzi 9.

Předpokládá se spíše využití pro doplňující grafiku (lepší vykreslování trajektorií a efekty).

Způsob implementace

Základem je sjednotit všechny animace pohybů pod jeden časovač a tím dosáhnout plynulého překreslování celého obrazu.

Zásadní je zde otázka optimalizace. Při běžné rychlosti překreslování 24 snímků za sekundu je zatížení prohlížeče příliš veliké.

Proto je třeba provést následující optimalizace:

Demo stt

Zajimavé souboryOdkaz na soubor
stt.jsZobrazit kód souboru testu s javascriptem
stt.htmlZobrazit kód souboru testu s html kódem

Demo stt.html demonstruje možnosti vykreslování pomocí css pro soustavu s pohybem po kružnici.

Planety mají zadánu úhlovou rychlost.

Řešení je funkční ve Firefoxu, Safari a Chrome ve verzích k lednu 2011. V IE nastavení pozic funguje, ale je zde jiný problém s proměnnými v javascriptu.

V Opeře dochází k problémům se zaokrouhlováním při násobení matic. Problém je pravděpodobně v použitém maticovém frameworku Sylvester, ale může se jednat i o bug v Opeře, protože při zapnutém dragonfly jsou výsledky výpočtů správné.

Tento problém lze odstranit vlastní implementací násobení matic, které by zároveň pomohlo i s optimalizací (napevno implementované násobení matic 3x3 oproti cyklům).

Toto demo není optimalizované a pohyb planet je zde mnohem rychlejší, než ten uvažovaný ve hře.

Obsah souboru stt.js


/// Tento soubor obsahuje experiment s vykreslování animace sluneční soustavy
/// s využitím CSS3.
/// Je použita kruhová dráha planet.

var $graphics = null;
var lastRenderT = 0;

/**
 * Vytvoření divu planety i s transformacemi pro innerHtml injection.
 */
function createPlanet(identifier, r, a, b, c, d, tx, ty)
{
    //console.log("createPlanet");
    return '<div class="planet" id="'+identifier+'" style="'+
            'width:'+r*2+'px;'+
            'height:'+r*2+'px;'+
            'border-radius:'+r+'px;'+
            '-moz-border-radius: '+r+'px;'+
            '-moz-transform: matrix('+a+','+b+','+c+','+d+','+tx+'px,'+ty+'px);'+
            '-webkit-transform: matrix('+a+','+b+','+c+','+d+','+tx+','+ty+');'+
            '-o-transform: matrix('+a+','+b+','+c+','+d+','+tx+','+ty+');'+
            'transform: matrix('+a+','+b+','+c+','+d+','+tx+','+ty+');'+
            '"></div>';
}

/**
 * Nastavení divu planety na požadované parametry.
 * Vytvoří kulatý div o požadovaném poloměru.
 * @param $identifier selector jquery pro div.
 * @param data data planety.
 */
function setPlanet($identifier, data)
{
    //console.log("setPlanet");
    $identifier.css({
        'border-radius': data.r+'px',
        '-moz-border-radius': data.r+'px',
        'width':data.r*2,
        'height':data.r*2
    })
}

/**
 * Sada funkcí pro generování transformačních matic.
 */
var GT = {
	// Rotace
    rotate: function(deg) {

        var rad = parseFloat(deg) * (Math.PI/180.0),
            costheta = Math.cos(rad),
            sintheta = Math.sin(rad);

        var a = costheta,
            b = sintheta,
            c = -sintheta,
            d = costheta;

        return $M([
          [a, c, 0.0],
          [b, d, 0.0],
          [0.0, 0.0, 1.0]
        ]);
    },

    // Scale
    scale: function (sx, sy) {
        sx = sx || sx === 0 ? sx : 1;
        sy = sy || sy === 0 ? sy : 1;
        return $M([
          [sx, 0,  0],
          [0,  sy, 0],
          [0,  0,  1]
        ]);
    },

    scaleX: function (sx) {
        return this.scale(sx);
    },

    scaleY: function (sy) {
        return this.scale(1, sy);
    },

    // Skew (Zkosení)
    skew: function (degX, degY) {
        var radX = parseFloat(degX) * (Math.PI/180),
            radY = parseFloat(degY) * (Math.PI/180),
            x = Math.tan(radX),
            y = Math.tan(radY);

        return $M([
          [1, x, 0],
          [y, 1, 0],
          [0, 0, 1]
        ]);
    },

    skewX: function (deg) {
        var rad = parseFloat(deg) * (Math.PI/180),
            x = Math.tan(rad);

        return $M([
          [1, x, 0],
          [0, 1, 0],
          [0, 0, 1]
        ]);

    },

    skewY: function (deg) {
        var rad = parseFloat(deg) * (Math.PI/180.0),
            y = Math.tan(rad);

        return $M([
          [1.0, 0.0, 0.0],
          [y, 1.0, 0.0],
          [0.0, 0.0, 1.0]
        ]);

    },

    // Posunutí.
    translate: function (tx, ty) {
        tx = tx ? tx : 0.0;
        ty = ty ? ty : 0.0;

        return $M([
          [1.0, 0.0, tx],
          [0.0, 1.0, ty],
          [0.0, 0.0, 1.0]
        ]);
    },

    translateX: function (tx) {
        return this.translate(tx);
    },

    translateY: function (ty) {
        return this.translate(0, ty);
    },

    // Generuje pole odpovídající matici transformace pro potřeby nastavení v css.
    toCssMatrix: function(matrix) {
        return [matrix.e(1,1), matrix.e(2,1),
            matrix.e(1,2), matrix.e(2,2), matrix.e(1,3), matrix.e(2,3)
        ];

        /*return [Math.round(matrix.e(1,1)), Math.round(matrix.e(2,1)),
            Math.round(matrix.e(1,2)), Math.round(matrix.e(2,2)), Math.round(matrix.e(1,3)), Math.round(matrix.e(2,3))
        ];*/
    },
    // Vypíše matici transformace. Pro ladící účely.
    toString: function(matrix) {
        return '['+matrix.e(1,1)+', '+matrix.e(2,1)+', '+matrix.e(1,2)+', '+matrix.e(2,2)+', '+matrix.e(1,3)+', '+matrix.e(2,3)+']';
    }
};

/**
 * Ruční nastavení transformační matice ve stylu elementu.
 * @param $identifier selektor elementu
 * @param matrix matice
 */
function setCssMatrix($identifier, matrix)
{
    var a = Math.round(matrix.e(1,1)),
        b = Math.round(matrix.e(2,1)),
        c = Math.round(matrix.e(1,2)),
        d = Math.round(matrix.e(2,2)),
        tx = Math.round(matrix.e(1,3)),
        ty = Math.round(matrix.e(2,3));

    $identifier.css({'-moz-transform':'matrix('+a+','+b+','+c+','+d+','+tx+'px,'+ty+'px)',
                    '-webkit-transform':'matrix('+a+','+b+','+c+','+d+','+tx+'px,'+ty+'px)',
                    '-o-transform':'matrix('+a+','+b+','+c+','+d+','+tx+'px,'+ty+'px)',
                    'transform':'matrix('+a+','+b+','+c+','+d+','+tx+'px,'+ty+'px)'});
}

/**
 * Renderovací funkce.
 */
function render()
{	
	// Zjištění aktuálního času
    var t = (new Date().getTime())/1000;
    var dt = t-lastRenderT;

    // Výpočet souřadnic počátku (uprostřed divu.
    var origin_x = $graphics.width()/2.0;
    var origin_y = $graphics.height()/2.0;

    // Transformační matice zobrazení (posune na střed divu)
    var TView = GT.translate(origin_x, origin_x);

    // Transformační matice polohy hvězdy.
    var TSun = GT.translate(sun.x0-sun.r, sun.y0-sun.r);

    // Nastavení polohy vhězdy.
    var m1 =  TView.x(TSun);
    $sun.transform({ matrix:  GT.toCssMatrix(m1)}, { preserve: false });

    // Výpis ladících údajů
    $('#timer').html(t+'; MSun='+GT.toString(m1)+'; TView='+GT.toString(TView)+'; TSun='+GT.toString(TSun));

    // Nastavení poloh planet.
    for(i=0;i<planets.length;i++) {
        var planet = planets[i];

        var m1 =  TView.x(planetCircularPositionMatrix(planet.data, t));
        planet.$id.transform({ matrix:  GT.toCssMatrix(m1)}, { preserve: false });
    }    
}

/**
 * Výpočet pozice planety na kruhové dráze.
 * Je zadána úhlová rychlost planety.
 * @param planet planeta
 * @param t čas
 * @returns transformační matice pro polohu planety v t.
 */
function planetCircularPositionMatrix(planet, t)
{
    var alpha = (planet.w*t)%360.0;
    var TPos = GT.translate(planet.x0, planet.y0);
    var RRot = GT.rotate(alpha);
    var TCorection = GT.translate(-planet.r, -planet.r);

    return TCorection.x(RRot.x(TPos));
}

Obsah souboru stt.html



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="cs">
  <head>

  	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<meta name="description" content="SpaceTraffic-description" />
	<meta name="author" xml:lang="cs" content="Space Traffic Team" />

	<meta http-equiv="Content-Style-Type" content="text/css" />

	<title>Space Traffic Test Page</title>

	<link rel="stylesheet" media="screen,projection,tv" href="/webgame_new/www/css/cssmap.css" type="text/css" />
	<!--<link rel="stylesheet" media="print" href="/webgame_new/www/css/print.css" type="text/css">-->
	<link rel="shortcut icon" href="/webgame_new/www/favicon.ico" type="image/x-icon" />

	<!--<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.js"></script>-->
        <script type="text/javascript" src="jquery-1.4.4.js"></script>

	<!--<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.8/jquery-ui.js"></script>-->
	<script type="text/javascript" src="jquery.transform-0.9.3.min.js"></script>
        <script type="text/javascript" src="sylvester.min.js"></script>
	<script type="text/javascript" src="stt.js"></script>
	<!-- <script type="text/javascript" src="/webgame_new/www/js/netteForms.js"></script> -->
        <script type="text/javascript">
            var transX = 0;
            var sun = null;
            var $graphics = null;

            // Definice planet
            var sun = {
                x0 : 0,
                y0 : 0,
                r  : 25,
                w  : 0
            };
            var planet1 = {
                x0 : 60,
                y0 : 0,
                r  : 5,
                w  : 18
            };

            var planet2 = {
                x0 : 90,
                y0 : 0,
                r  : 8,
                w  : 6
            };

            var planet3 = {
                x0 : 130,
                y0 : 0,
                r  : 15,
                w  : 7
            };

            var planet4 = {
                x0 : 150,
                y0 : 0,
                r  : 14,
                w  : 3
            };

            var planet9 = {
                x0 : 180,
                y0 : 0,
                r  : 59,
                w  : 3
			};

            var planets = null;

			// Inicializace renderování.
           $(document).ready(function() {
                //console.log("ready");
                $sun=$(".sun");
                $planet1 = $("#planet1");
                $planet2 = $("#planet2");
                $planet3 = $("#planet3");
                $planet4 = $("#planet4");
                $planet9 = $("#planet9");
                setPlanet($sun, sun);
                setPlanet($planet1, planet1);
                setPlanet($planet2, planet2);
                setPlanet($planet3, planet3);
                setPlanet($planet4, planet4);
                planets = [{$id: $planet1, data: planet1},
                    {$id: $planet2, data: planet2},
                    {$id: $planet3, data: planet3},
                    {$id: $planet4, data: planet4},
                    {$id: $planet9, data: planet9}
                ];
                $graphics = $("#graphics");
                render();
                setInterval('render()',50);
            });


        </script>

    <link rel="start" href="/webgame_new/www" title="Home" />
	<link rel="stylesheet" media="screen,projection,tv" href="stt.css" type="text/css" />
  </head>
  <body>
    <div id="envelope">
      <div id="header">
        <h1>Space Traffic Test Page</h1>
        <div style="text-align: right; margin: 0 10px 2px 10px;">&nbsp;<!--<span>Czech | English</span>--></div>
      </div>
      <div id="content">
      	<div id="topPanel">
      		<div class="topbrick"><p>Space Traffic</p></div>
      		<div class="topbrick"><p>5/8</p><p>Lodě</p></div>
      		<div class="topbrick"><p>10/8</p><p>Základny</p></div>
      		<div class="topbrick"><p>10/8</p><p>Zprávy</p></div>
      		<div class="topbrick"><p>Prachy</p></div>
      	</div>
      	<div id="menuPanel">

      		<h2>Menu</h2>
			<ul class="mainmenu">
				<li><a class="ajax" href="#">Events</a></li>
				<li><a class="ajax" href="#">Ships</a></li>
				<li><a class="ajax" href="#">Bases</a></li>
				<li><a class="ajax" href="#">Messages</a></li>
				<li><a class="ajax" href="#">Map</a></li>
				<li><a class="ajax" href="#">Scoreboard</a></li>
				<li><a class="ajax" href="#">Profile</a></li>
				<li><a class="ajax" href="#">Help</a></li>	
			</ul>

      	</div>
      	<div id="mainPanel">
      		<div id="graphics">
                    <span id="timer"></span>
                    <div class="crossair" ></div>
                    <div class="sun">&nbsp;</div>
                    <div class="planet" id="planet1">1</div>
                    <div class="planet" id="planet2">2</div>
                    <div class="planet" id="planet3">3</div>
                    <div class="planet" id="planet4">4</div>
                    <div class="planet9" id="planet9"><img width="30px" height="30px" src="images/solarsystem/planets/zeme.png" ></div>
                    <div class="orbit"></div>
      		</div>
                <div id="graphics2">
                </div>
      	</div>
      	<div id="contextPanel">

      	</div>

	  </div>
	  <div id="footer">
	  	<p>&copy; Space Traffic Team | <span xml:lang="cs">ZCU</span> | <span xml:lang="cs">FAV</span> | <span xml:lang="cs">KIV</span></p>
		<p xml:lang="cs">Sources for background images were taken by Hubble Space Telescope and published by NASA.</p>
	  </div>
	</div>
  </body>
</html>





Zpět na HomePage

Retrieved from http://wiki.kiv.zcu.cz/SpaceTraffic/TestPohybPlanet1
Content last modified on 24 January 2011, 03:16