Показать сообщение отдельно
Старый 27.09.2010, 02:21   #2
jimon
 
Сообщений: n/a
Ответ: Qt QML : декларативный интерфейс, императивная логика

чтобы опробовать инструмент решил написать понг чисто на QML, в принципе результирующий код вышел немного громоздким из-за асинхронного javascript кода и qml анимаций

мышкой управляются обе платформы, скорость игры постепенно увеличивается, необходимо набрать наибольшее количество очков

// imports
import Qt 4.7

// root object
Rectangle
{
	id:screen; width:1024; height:768; color:"#DDDDDD"

	// game text, show status of the game
	Text
	{
		id:gameText;
		anchors.top:screen.top; anchors.horizontalCenter:screen.horizontalCenter
		text:"QML pong by jimon"
	}

	// score text
	Text
	{
		id:gameScoreText;
		anchors.top:screen.top; x:5;
		font.family: "Courier New"; font.pointSize: 16; color: "#000000"

		function zeroPad(num, count)
		{
			while(num.length < count) num = "0" + num;
			return num;
		}

		function setScore(score)
		{
			text = "SCORE : " + zeroPad(score.toString(), 7)
		}

		Component.onCompleted:setScore(0);
	}

	// ball
	Rectangle
	{
		id:ball; width:64; height:64; color:"#000000"
		x:(screen.width - ball.width) / 2; y:(screen.height - ball.height) / 2

		property variant wayX: 0 // ball way X
		property variant wayY: 0 // ball way Y
		property double speed: 0
		property double speedDefault: 0.25 // in pixels per millisec

		// moving, use number animation on x and y, calculate duration by hands
		// moving by javascript and etc is a really BAD idea

		NumberAnimation on x {id:ballAnimX}
		NumberAnimation on y {id:ballAnimY}

		function moveTo(newV, oldV, anim)
		{
			anim.stop();
			anim.duration = Math.abs(oldV - newV) / speed;
			anim.from = oldV;
			anim.to = newV;
			anim.start();
		}

		function moveToX(newX)
		{
			moveTo(newX, ball.x, ballAnimX)
		}

		function moveToY(newY)
		{
			moveTo(newY, ball.y, ballAnimY)
		}

		function stopAnimations()
		{
			ballAnimX.stop();
			ballAnimY.stop();
		}

		function setWayX(newWayX)
		{
			if(newWayX != wayX)
			{
				ball.moveToX(newWayX == 1 ? screen.width - ball.width : 0);
				wayX = newWayX;
			}
		}

		function setWayY(newWayY)
		{
			if(newWayY != wayY)
			{
				ball.moveToY(newWayY == 1 ? screen.height - ball.height : 0);
				wayY = newWayY;
			}
		}
	}

	// left platform
	Rectangle
	{
		id:left; width:32; height:128; color:"#5555FF"; anchors.left:screen.left
		y:(screen.height - left.height) / 2
	}

	// right platform
	Rectangle
	{
		id:right; width:32; height:128; color:"#5555FF"; anchors.right:screen.right
		y:(screen.height - right.height) / 2
	}

	// game logic timer
	Timer
	{
		interval:20; running:true; repeat:true
		onTriggered:gameTick();
	}

	// work with mouse
	MouseArea
	{
		id:mouse;
		anchors.fill:screen; hoverEnabled:true
		onPositionChanged:gameUpdateMouse();
		onClicked:gameRestart();
	}

	property variant gameCanRestart:1;
	property variant gameScore:0;

	function gameTick()
	{
		if(!gameCanRestart) // if game running
		{
			gameScore = gameScore + 10;
			gameScoreText.setScore(gameScore);

			ball.speed = ball.speed * 1.001;
		}

		if(gamePlatformCheck(left)) // horizontal moving
			ball.setWayX(1);
		if(gamePlatformCheck(right))
			ball.setWayX(-1);
		else if(ball.x <= 0 || ball.x >= screen.width - ball.width)
			screen.gameLose();

		if(ball.y >= screen.height - ball.height) // vertical moving
			ball.setWayY(-1);
		else if(ball.y <= 0)
			ball.setWayY(1);
	}

	function gamePlatformCheck(platform)
	{
		return (Math.abs(platform.x - ball.x + (platform.width - ball.width) / 2) < (platform.width + ball.width) / 2) &&
		   (Math.abs(platform.y - ball.y + (platform.height - ball.height) / 2) < (platform.height + ball.height) / 2);
	}

	function gameUpdateMouse()
	{
		left.y = mouse.mouseY - left.height / 2;
		right.y = mouse.mouseY - right.height / 2;
	}

	function gameLose()
	{
		gameText.text = "Game Over !";
		ball.stopAnimations();
		ball.x = (screen.width - ball.width) / 2;
		ball.y = (screen.height - ball.height) / 2;

		gameCanRestart = 1;
	}

	function gameRestart()
	{
		if(gameCanRestart)
		{
			gameScore = 0;
			gameScoreText.setScore(gameScore);

			ball.speed = ball.speedDefault;

			ball.wayX = 0;
			ball.wayY = 0;
			ball.setWayX(-1);
			ball.setWayY(-1);
			gameText.text = "Game Started !";
			gameCanRestart = 0;
		}
	}
}
основная громоздкость в необходимости хранить направление движения, потому что функция moveTo выполняется асинхронно с анимациями и может банально не дать анимации стартовать

подход выполнения логики в javascriptе мне совсем не понравился, он слишком сырой сейчас, попробую еще реализовать логику на C++
Миниатюры
Нажмите на изображение для увеличения
Название: snapshot1.png
Просмотров: 1087
Размер:	4.6 Кб
ID:	11374  
 
Ответить с цитированием