Jump to content
Search Community

Peggle style game - Need help optimising

ilovemypixels test
Moderator Tag

Recommended Posts

Hi there,

 

I have made myself a little game loosely based on peggle. You can have a look here:-

 

http://www.ourtestsite.org/antigravitysnowballgame/

 

Currently it uses Greensocks Physics2DPlugin and MotionBlurPlugin. It works o.k. but I would really appreciate anything you can spot that might make it run smoother. It also runs differently every time and sometimes the ball overlaps the pegs. I have the peg and boundary hit checks running using greensocks onUpdate feature but I'm not sure if this is the best way.

 

Thanks for any help. If you manage to help make it smoother then you can feel free to use my code to make your own game but please don't copy it 100%.

 

Any other comments are greatly appreciated.

 

Will

 

stop();
mainTL = this;

import com.greensock.*;
import com.greensock.easing.*;
import com.greensock.plugins.*;

TweenPlugin.activate([Physics2DPlugin, MotionBlurPlugin]);
//TweenPlugin.activate([Physics2DPlugin]);
ball.cacheAsBitmap = true;

// Variables
var gravity:Number = 500;
var totalPegs:Number = 15;
var pegRadius:Number = 10;
var ballRadius:Number = 20;

// Constants
var collisionRadius:Number = pegRadius + ballRadius;
var leftBorder:Number = 0;
var rightBorder:Number = Stage.width;
var topBorder:Number = 0;
var bottomBorder:Number = Stage.height + (ballRadius*2) + 20;
var activePegs:Array = new Array();
var mBStrength:Number = 0.5;
var mBQuality:Number = 0;
var reboundVelocity:Number = 350;
var dHitNum:Number = 0;
var bNum:Number = 0;
var lastSecSaveGot:Boolean = false;
var gameStatus:String = "idle";
var mainScore:Number = 0;
var myHighScore:Number = 0;
var hitsNoClicks:Number = 0;
var offTheWall:Boolean = false;

// Initial setup
clickArea._width = rightBorder;
clickArea._height = bottomBorder;
ballPlatform._y = 570;

for(i=0; i	activePegs[i] = mainTL["peg" + i];
mainTL["_level0." + i + "hit"] = false;
}

startAd();

function startAd() {
getSharedData();

offScreenMarker._visible = false;

TweenMax.killTweensOf(ball);
ball._x = 500;
ball._y = 544;
ballRadius = 20;
ball._xscale = 100;
ball._yscale = 100;
ball.hotSpot._xscale = 100;
ball.hotSpot._yscale = 100;
ball.snow_whirl._xscale = 100;
ball.snow_whirl._yscale = 100;

mainScore = 0;
}

function getSharedData() {
//////////
user = SharedObject.getLocal("user_profile");

//user.clear();

if (user.data.score == undefined){
	myHighScore = 0;
	myHighScore_txt.text = "High Score: " + myHighScore;
} else {
	myHighScore = user.data.score;
	myHighScore_txt.text = "High Score: " + myHighScore;
}
}

function saveSharedData() {
	user.data.score = mainScore;
	user.flush();
	myHighScore_txt.text = "High Score: " + user.data.score;
	gotoAndStop('submit_score');
}

// Ball interaction
clickArea.onPress = function() {
ballPressed = true;
ballActive = false;
}

clickArea.onRelease = function() {
if(gameStatus != "gameover"){
	mainScore -= 100;

	if(gameStatus == "idle"){
		TweenLite.to(ballPlatform, 1, {_y:620, ease:Quad.easeOut, overwrite:false});
	}

	gameStatus = "active";

	TweenMax.killTweensOf(ball);
	ballPressed = false;
	ballActive = true;

	hitsNoClicks = 0;
	offTheWall = false;

	if(ball._y > 640 && lastSecSaveGot == false){
		lastSecSaveGot = true;

		drawBonus("lastSecondSave");
	}

	var storeVelocity:Number = (getDistance(ball._x, ball._y, _xmouse, _ymouse))*2;

	if(storeVelocity <= 400){
		storeVelocity = 400;
	}

	TweenMax.to(ball, 20, {physics2D:{velocity:storeVelocity, angle:pingArrow._rotation, gravity:gravity}, onUpdate:doChecks, motionBlur:{strength:mBStrength, quality:mBQuality}});
}
}

function toDegrees(radians) :Number{
var degrees = radians * 180/Math.PI
return degrees;
}

function getAngleOf(x1,y1,x2,y2):Number{
var dx = x2-x1;
var dy = y2-y1;
var angle = Math.atan2(dy,dx);
return toDegrees(angle);
}

function getDistance(x1, y1, x2, y2) {
xdist = Math.round(x1 - x2);
ydist = Math.round(y1 - y2);
distanceFromThis = Math.sqrt((xdist*xdist) + (ydist*ydist));
return distanceFromThis;
}

function drawPingArrow() {

pingArrow._visible = true;
pingArrow._x = ball._x;
pingArrow._y = ball._y;

pingArrow._rotation = getAngleOf(ball._x, ball._y, _xmouse, _ymouse);

if(getDistance(ball._x, ball._y, _xmouse, _ymouse) <= 100){
	pingArrow._xscale = getDistance(ball._x, ball._y, _xmouse, _ymouse);
	pingArrow._yscale = getDistance(ball._x, ball._y, _xmouse, _ymouse);
} else {
	pingArrow._xscale = 100;
	pingArrow._yscale = 100;
}

}

function hidePingArrow() {
pingArrow._visible = false;
pingBar._visible = false;
}

function ballDied() {
ball._x = 200;
//ball._y = 
}

function checkBorders(){
if(ball._x >= rightBorder - ballRadius){
	TweenMax.killTweensOf(ball);
	ball._x = (rightBorder - ballRadius)-4;
	offTheWall = true;

	//Bounce off
	TweenMax.to(ball, 20, {physics2D:{velocity:(reboundVelocity/2), angle:180, gravity:gravity}, onUpdate:doChecks, motionBlur:{strength:mBStrength, quality:mBQuality}});
} else if (ball._x <= leftBorder + ballRadius){
	TweenMax.killTweensOf(ball);
	ball._x = leftBorder + ballRadius;
	offTheWall = true;

	//Bounce off
	TweenMax.to(ball, 20, {physics2D:{velocity:(reboundVelocity/2), angle:0, gravity:gravity}, onUpdate:doChecks, motionBlur:{strength:mBStrength, quality:mBQuality}});
}

if(ball._y >= bottomBorder - ballRadius){
	TweenMax.killTweensOf(ball);
	ball._y = bottomBorder - ballRadius;

	// Do death thing
	TweenMax.killTweensOf(ball);
	gameStatus = "gameover";
	delete onEnterFrame;
	gameOver();
}

}

function checkHit(targetMc, pegNum){

if(getDistance(ball._x, ball._y, targetMc._x, targetMc._y) <= collisionRadius){
	// Add 500 to scroe
	mainScore += 500;

	TweenMax.killTweensOf(ball);

	hitsNoClicks++;

	//TweenLite.to(ball.hotSpot, 1, {_xscale:"10", _yscale:"10", ease:Quad.easeOut, overwrite:false});
	//TweenLite.to(ball.snow_whirl, 1, {_xscale:"10", _yscale:"10", ease:Quad.easeOut, overwrite:false});

	mainTL[targetMc + "hit"] = true;

	// Remove deleted peg from array
	//trace(targetMc);

	activePegs.splice(pegNum, 1);

	// Explode peg
	targetMc.gotoAndPlay('explode');

	if(hitsNoClicks >= 2){
		drawHitGraphics(targetMc._x, targetMc._y, hitsNoClicks);
	}

	if(offTheWall == true){
		offTheWall = false;
		drawBonus("offTheWall")
		mainScore += 500;
	}

	var hitAngle = getAngleOf(ball._x, ball._y, targetMc._x, targetMc._y);

	TweenMax.to(ball, 20, {physics2D:{velocity:reboundVelocity, angle:hitAngle - 180, gravity:gravity}, onUpdate:doChecks, motionBlur:{strength:mBStrength, quality:mBQuality}});
}
}

function doChecks(){
checkBorders();

for(i=0; i		checkHit(activePegs[i], i);
}
}

function drawHitGraphics(spawnX, spawnY, numHits) {
//trace(spawnX);
//trace(spawnY);

attachMovie("hitGraphic" + numHits, "dHit" + dHitNum, mainTL.getNextHighestDepth());

mainTL["dHit" + dHitNum]._xscale = 1;
mainTL["dHit" + dHitNum]._yscale = 1;
mainTL["dHit" + dHitNum]._x = spawnX;
mainTL["dHit" + dHitNum]._y = spawnY;

TweenLite.to(mainTL["dHit" + dHitNum], 0.5, {_xscale:100, _yscale:100, ease:Elastic.easeOut, overwrite:false});
mainScore += (1000*(numHits*0.5));
TweenLite.to(mainTL["dHit" + dHitNum], 0.5, {_alpha:0, overwrite:false, delay:1.5, onComplete:deleteIt, onCompleteParams:[mainTL["dHit" + dHitNum]]});

dHitNum++;
}

function drawBonus(tBonus){
attachMovie(tBonus, "bClip" + bNum, mainTL.getNextHighestDepth());
mainTL["bClip" + bNum]._xscale = 1;
mainTL["bClip" + bNum]._yscale = 1;

if(tBonus == "lastSecondSave"){
	mainTL["bClip" + bNum]._x = ball._x;
	mainTL["bClip" + bNum]._y = 570;
} else if (tBonus == "offTheWall"){
	mainTL["bClip" + bNum]._x = ball._x;
	mainTL["bClip" + bNum]._y = ball._y;
}

TweenLite.to(mainTL["bClip" + bNum], 0.5, {_xscale:100, _yscale:100, ease:Elastic.easeOut, overwrite:false});
TweenLite.to(mainTL["bClip" + bNum], 0.5, {_alpha:0, overwrite:false, delay:1.5, onComplete:deleteIt, onCompleteParams:[mainTL["bClip" + bNum]]});

bNum++;
}

function drawOffScreenMarker(){

offScreenMarker._x = ball._x
offScreenMarker._visible = true;
}

function hideOffScreenMarker(){

offScreenMarker._visible = false;
}

function gameOver() {
TweenMax.killTweensOf(gameOver2);
attachMovie("gameOver", "gameOver2", mainTL.getNextHighestDepth());
gameOver2._yscale = 1;
gameOver2._xscale = 1;
gameOver2._x = 500;
gameOver2._y = 300;

TweenLite.to(gameOver2, 0.5, {_xscale:100, _yscale:100, ease:Elastic.easeOut, overwrite:false});
TweenLite.to(gameOver2, 0.5, {_alpha:0, overwrite:false, delay:1.5, onComplete:gameOverDone});
}

function gameOverDone() {
deleteIt(gameOver2);

if(mainScore > myHighScore){
	saveSharedData();
} else {
	gotoAndStop('low_score');
}
}

function deleteIt(dTarget) {
//trace(dTarget);
//trace("del it");
removeMovieClip(dTarget);
}

onEnterFrame = function(){
	guide_hitsNoClicks.text = hitsNoClicks;
	collisionRadius = pegRadius + ballRadius;
	ballRadius = (ball.hotSpot._width/2);
	bottomBorder = Math.floor(Stage.height + (ballRadius*2) + 20);
	//trace(bottomBorder);

	mainScore_txt.text = "Score: " + mainScore;

	//guideArray.text = activePegs;
	// Draw ping arrow
	if(ballPressed == true){
		drawPingArrow();
	} else {
		hidePingArrow();
	}

	if (ball._y <= topBorder + ballRadius){
		drawOffScreenMarker();
	} else {
		hideOffScreenMarker();
	}
}

Link to comment
Share on other sites

is this Will Daddy of Sucka Swing? http://www.kongregate.com/games/Groady/sucka-swing

 

 

either way...

very cool game. I hated it until I realized I could click again after the ball was launched :) once I got past that it was a lot more fun.

 

I felt the performance was quite good. never saw any lag or anything.

 

what are your performance comparisons between motionBlur on and off?

to me motionBlur adds the most visual oomph on the high velocity tweens. perhaps only use motionBlur if the initial velocity is within a certain range. maybe it will look like crap. i don't know;)

 

also, does the motionBlur affect the accuracy of the peg collision? I have no idea, just curious.

 

by looking at your code I can vaguely visualize how it all works. without studying it indepth I don't know that any huge performance optimizations are going to jump out at me.

 

the only super minor thing i saw was that I've heard that it is better when doing for loops to use:

 

var max:int = activePegs.length;

for(i=0; i      checkHit(activePegs[i], i);
  }

 

instead of this

 

 for(i=0; i      checkHit(activePegs[i], i);
  }

 

in the first snippet flash only has to access the length of the array once. you may save 3ms here but sometime in the future it might be handy.

i highly doubt it makes any difference when you are only looping through a dozen or so items.

 

for the most part it seems like you only have one ball tween running at any given time and its just performing a number of checks onUpdate.

 

I don't know if a master ENTER_FRAME loop would behave any differently. my understanding is that onUpdate is virtually the same thing.

 

I'm very impressed with how playable and enjoyable the game is and the fact that the code isn't totally insane is remarkable!

 

 

c

Link to comment
Share on other sites

Aww .. thanks man. That made my afternoon.

 

I'll try the for loop thing it's a good point.

As for the motion blur it doesn't seem to affect performance much at all really. I think the main reason it doesn't seem that smooth to me, is that this was based on another interactive banner I made where I did everything using Xspeed and Yspeed variables. These got updated on every frame adding the speed to the X and Y position. This seemed much smoother but I wanted to make my game using greensock as calculating the angle and velocities would have been a headache doing it the other way. (this probably makes no sense to anyone else) but describing the angle and velocity in a tween is much easier than calculating the angle using trigonometry.

 

My main problem then is to do with the ball overlapping the pegs at points. I have seen normal hitTest code that would set the ball back to the right position on collision. This is easy when your object hits a horizontal plane but my pegs are round. So on collision I would have to work out the angle and then the maximum distance to move the ball so it was at the pegs edge. I'm not sure how to do this.

 

Sorry if all this makes no sense at all. I'm in too deep now.

 

Any more help is greatly appreciated.

 

Thanks

 

Will

 

P.s. No I didn't make sucka swing.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...