"use strict";

var WIDTH  = 480;
var HEIGHT = 360;
var LENGTH = 64000;


var Car = class extends TUGames.Sprite
{
	constructor( textile, cidx )
	{
		super( 32, 64, textile, cidx, 1, 2 );
		this.mDX = 0;
		this.mSpeed = 0;
	}
}


var Enemy = class extends Car
{
	constructor( textile, spd )
	{
		super( textile, 25 );
		this.X = TUGames.UT.Rnd( 200 ) + 140 - 16;
		this.Y = -64;
		this.mDX = ( TUGames.UT.Rnd( 13 ) - 6 ) / 4.0;
		this.mSpeed = TUGames.UT.Rnd( spd ) + 10000;
	}
}


var Player = class extends Car
{
	constructor( textile )
	{
		super( textile, 24 );
		this.mBrake = 0;
		this.mSpeed = 6000;
		this.X = WIDTH / 2 - 16;
		this.Y = HEIGHT - 80;
	}

	tick()
	{
		if( TUGames.PF.IsKeyDown( 37 ) ){	//	引数で指定されたキーが押されている場合
			if( this.mDX == 0 ){
				this.X -= 2;
				this.mSpeed -= 50;
			}else if( this.mDX < 0 && this.mDX > -2 ){
				this.mDX = 0;
			}
		}
		if( TUGames.PF.IsKeyDown( 39 ) ){	//	引数で指定されたキーが押されている場合
			if( this.mDX == 0 ){
				this.X += 2;
				this.mSpeed -= 50;
			}else if( this.mDX > 0 && this.mDX < 2 ){
				this.mDX = 0;
			}
		}
		if( TUGames.PF.IsKeyDown( 90 ) ||
		    TUGames.PF.IsKeyDown( 40 ) ){	//	引数で指定されたキーが押されている場合
			this.mSpeed = Math.max( 6000, this.mSpeed - 500 );
			this.mBrake = true;
		}

		this.mSpeed += Math.min( 50, 1000000 / this.mSpeed );
		this.X += this.mDX;
		this.mDX -= Math.sign( this.mDX ) * Math.min( Math.abs( this.mDX ), 0.02 );
	}
}


var	Map =
[
	[
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
		[ 5, 5, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 1, 1, ],
	],[
		[ 9, 9,10,10,16,18, 8,20,21, 8,19,17, 9, 8, 8, 8, ],
		[ 9, 9,10,10,16, 8, 8, 8, 8, 8, 8,17, 9, 8, 8, 8, ],
		[ 9, 8, 8, 8,16,18, 8,20,21, 8,19,17, 8, 8, 8, 8, ],
		[ 9, 8, 8, 8,16, 8, 8, 8, 8, 8, 8,17, 8, 8, 8, 8, ],
		[ 9, 9, 9, 9,16,18, 8,20,21, 8,19,17, 9, 8, 8, 8, ],
		[ 9, 9, 9, 9,16, 8, 8, 8, 8, 8, 8,17, 9, 8, 8, 8, ],
		[ 9, 8, 8, 8,16,18, 8,20,21, 8,19,17, 8, 8, 8, 8, ],
		[ 9, 8, 8, 8,16, 8, 8, 8, 8, 8, 8,17, 8, 8, 8, 8, ],
		[ 9, 9,10,11,16,18, 8,20,21, 8,19,17, 9, 8, 8, 8, ],
		[ 9, 9,10,10,16, 8, 8, 8, 8, 8, 8,17, 9, 8, 8, 8, ],
		[ 9, 8, 8, 8,16,18, 8,20,21, 8,19,17, 8, 8, 8, 8, ],
		[ 9, 8, 8, 8,16, 8, 8, 8, 8, 8, 8,17, 8, 8, 8, 8, ],
		[ 9, 9, 9, 9,16,18, 8,20,21, 8,19,17, 9, 8, 8, 8, ],
		[ 9, 9, 9, 9,16, 8, 8, 8, 8, 8, 8,17, 9, 8, 8, 8, ],
		[ 9, 8, 8, 8,16,18, 8,20,21, 8,19,17, 8, 8, 8, 8, ],
		[ 9, 8, 8, 8,16, 8, 8, 8, 8, 8, 8,17, 8, 8, 8, 8, ],
	]                              
];

function start( im )
{
	TUGames.GX.Init( "main", 480, 360 );	//	キャンバスIDと描画領域を指定してライブラリ初期化

	let	tex = TUGames.Texture.Create( 0x80, 0x80 );
	tex.texSubImage2D( 0x00, 0x00, TUGames.TURawImage.CreateFromImage( im[ 0 ], 16 ) );
	tex.texSubImage2D( 0x00, 0x40, TUGames.TURawImage.CreateFromImage( im[ 1 ], 16 ).clone( 0, 20, 128, 60 ) );

	let	ttc = new TUGames.TexTile( tex, 8, 0.5 / 8, 0.5 / 8 );
	let	field = new TUGames.BG( new TUGames.PriTile( 16, 16, 32, 32, 2, ttc ) );
	field.setIndex_A3( Map );

	let	tf = new TUGames.TexFont( new TUGames.TexTile( tex, 16, 8 / 128.0, 10 / 128.0, 0.0, 0.5 ) );
	tf.initHCode( 0x40, 0x20 );
	let	pt = [];
	pt[ 0 ] = TUGames.PriStr.Create( "TIME" , tf,  4, 28 * 1 + 6, 0xffffffff, 0xffffffff, 0xff000000 );
	pt[ 1 ] = TUGames.PriStr.Create( ""     , tf, 12, 28 * 2 + 6, 0xffffffff, 0xffffffff, 0xff000000 );
	pt[ 2 ] = TUGames.PriStr.Create( "SPEED", tf,  4, 28 * 4 + 6, 0xffffffff, 0xffffffff, 0xff000000 );
	pt[ 3 ] = TUGames.PriStr.Create( ""     , tf, 12, 28 * 5 + 6, 0xffffffff, 0xffffffff, 0xff000000 );

	let	player = new Player( ttc, 24 );
	let	enemy = [];

	let	py = 0;
	let	ani = -1;
	TUGames.PF.StartLoop( 60,	//	fpsを指定してループを開始し、更新処理と描画処理を登録	
//	TUGames.PF.StartLoop( 1,	//	fpsを指定してループを開始し、更新処理と描画処理を登録	
	()=>{	//	更新処理
		if( py - LENGTH > -0x200 && Map[ 1 ][ 0 ][ 4 ] == 16 ){	//	ゴール目前に迫った場合
			Map[ 1 ][ 0 ][  4 ] = 13;
			Map[ 1 ][ 0 ][  5 ] = 13;
			Map[ 1 ][ 0 ][  6 ] = 13;
			Map[ 1 ][ 0 ][  7 ] = 14;
			Map[ 1 ][ 0 ][  8 ] = 15;
			Map[ 1 ][ 0 ][  9 ] = 13;
			Map[ 1 ][ 0 ][ 10 ] = 13;
			Map[ 1 ][ 0 ][ 11 ] = 13;
			field.setIndex_A3( Map );
		}
		if( py - LENGTH > -0x200 + 276 ){	//	ゴールした場合
			player.mSpeed = 0;
			return;
		}

		let		tm = Math.floor( TUGames.PF.Count * 100 / 60 );
		let		st = "" + Math.floor( tm / 100 ) + "." + Math.floor( tm / 10 % 10 ) + ( tm % 10 );
		pt[ 1 ].setString( st.padStart( 6, ' ' ) );

		if( ani == 0 ){	//	衝突した場合
//			wo.playDB( exp );
			player.mSpeed = 0;
			player.setCClm( 2 );
			player.setWH( 64, 64 );
			player.setCIdx( 40 );
			player.X -= 16;
			ani = 1;
		}

		if( ani > 0 ){	//	爆発アニメ中の場合
			++ani;
			if( ( ani & 7 ) == 0 ){
				let	i = ani >> 2;
				if( i < 8 ){
					player.setCIdx( 40 + i );
				}
			}
			if( ani == 100 ){
				ani = -1;
				player.X = WIDTH / 2 - 16;
				player.setCClm( 1 );
				player.setWH( 32, 64 );
				player.setCIdx( 24 );
				player.mDX = 0;
				player.mSpeed = 1000;
			}
		}

		if( ( player.X < WIDTH / 2 - 16 - 112 || player.X > WIDTH / 2 - 16 + 112 ) && player.mSpeed >= 6000 && ani < 0 ){	//	壁に激突した場合
			ani = 0;
		}

		player.tick();
		if( ani >= 0 ){
			player.mSpeed = 0;
		}

		let		ps = Math.floor( player.mSpeed / 2.0 );
		let		s = Math.floor( ps / 100 ) + "." + ( Math.floor( ps / 10 ) % 10 ) + ( ps % 10 );
		pt[ 3 ].setString( s.padStart( 6, ' ' ) );

		if( ani < 0 ){
			py += player.mSpeed / 4096;
		}

		let	ds = player.mSpeed - 10000;
		if( ds > 1000 && TUGames.UT.Rnd( 30 + enemy.length * 40 ) == 0 ){
			enemy.push( new Enemy( ttc, ds ) );
		}

		for( let i = enemy.length - 1; i >= 0; i-- ){
			let	e = enemy[ i ];
			if( ani < 0 && player.isCollision( e ) ){
				let		dx = e.X - player.X;
				let		dy = e.Y - player.Y;
				let		ss = player.mSpeed;
				player.mSpeed = e.mSpeed;
				e.mSpeed = ss;
				player.mDX = -dx / 16;
				e.mDX = dx / 16;
			}
			e.X += e.mDX;
			e.Y += ( player.mSpeed - e.mSpeed ) / 4096;
			if( e.X > WIDTH / 2 + 112 - 16 && e.mDX > 0 ){
				e.mDX = -e.mDX;
			}
			if( e.X < WIDTH / 2 - 112 - 16 && e.mDX < 0 ){
				e.mDX = -e.mDX;
			}
			if( e.Y > 360 ){
				enemy.splice( i, 1 );
			}
		}

/*
		if( wo.getFlagDoneDB() ){
			if( !player.mBrake && player.mDX == 0 ){
				wo.playDB( TUGames.TUWaveOut.CreateSquare( player.mSpeed / 512.0f, 100, 0x2000 ) );
			}else{
				wo.playDB( bra );
				player.mBrake = false;
			}
		}

		if( wobgm.getFlagDoneDB() ){
			wobgm.playDB( wavbgm );
		}
*/
	},
	()=>{	//	描画処理
		TUGames.GX.Clear();	//	設定された背景色で画面初期化
		field.drawFull( -16, Math.floor( py - LENGTH ), WIDTH, HEIGHT );
		player.draw();
		for( let i = 0; i < enemy.length; i++ ){
			enemy[ i ].draw();
		}
		for( let i = 0; i < pt.length; i++ ){
			pt[ i ].draw();
		}
		GL.flush();	//	描画内容を画面に反映
	} );
}


window.onload = function()
{
	document.addEventListener( 'keydown', ( ev ) =>{	ev.preventDefault();	} );
	document.addEventListener( 'keyup'  , ( ev ) =>{	ev.preventDefault();	} );

	let	fn = [ "../assets/8x8_4c_2bpp.png", "../assets/font_8x10.png" ];
	let	im = new Array( fn.length );
	let	cnt = 0;
	for( let i = 0; i < fn.length; i++ ){
		im[ i ] = new Image();
		im[ i ].onload = function()
		{
			if( ++cnt == fn.length ){
				start( im );
			}
		}
		im[ i ].src = fn[ i ];
	}
}


戻る戻る back