How to write a loop that will check if lives === 0? - html

I am making a very simple html5 canvas game. I wish to make it so that when the player loses all 3 lives the game resets.
I was thinking I could do a while loop where it always checks for Lives === 0 then run a function but this breaks the game and nothing shows up on the canvas.
here is my code.
var lives = 3;
while (lives <= 0) {
var fullReset = function () {
// Throw the monster somewhere on the screen randomly
monster.x = 1 + (Math.random() * (canvas.width - 64));
monster.y = 1 + (Math.random() * (canvas.height - 64));
monster2.x = 1 + (Math.random() * (canvas.width - 100));
monster2.y = 1 + (Math.random() * (canvas.height - 100));
// player start again
hero.x = canvas.width / 2;
hero.y = canvas.height / 2;
//score resets
monstersCaught() = 0;
lives() = 3;
}
fullReset();
}

I think there is a conceptual bug in your approach. You start with 3 lives (initialization that is missing in your example). Then, every time the monster attacks, you reduce the lives by one and check the new value. When the new value is zero, then it is time to reset the game.
So, your loop should only handle moving your object while you would trigger an event whenever the monster attacks and apply the above logic.

function gameLoop() {
var lives = 3;
if(lives <= 0) {
var fullReset = function () {
// Throw the monster somewhere on the screen randomly
monster.x = 1 + (Math.random() * (canvas.width - 64));
monster.y = 1 + (Math.random() * (canvas.height - 64));
monster2.x = 1 + (Math.random() * (canvas.width - 100));
monster2.y = 1 + (Math.random() * (canvas.height - 100));
// player start again
hero.x = canvas.width / 2;
hero.y = canvas.height / 2;
//score resets
monstersCaught() = 0;
lives() = 3;
}
fullReset();
}
requestAnimationFrame(gameLoop);
}
have you tried the requestAnimationFrame() this way you might not even depend on the while loop and draw canvas over and over again with changed positions of objects everytime.

That isn't a very practical way to solve your problem.
I would handle that with an OnEvent trigger such as when a monster attacks or when the player touches the monster

Related

Actionscript: Very slow movieclip

I am drawing a circular line to varying degrees. I wish the animation to last about 0.5 seconds. For reasons I can not work out its running very slowly.
What is weird is that if I skip the tween and call the function tweenToNext it renders instantly.
var degrees:int;
var posX:int = 102;
var posY:int = 102;
var rad:int = 100;
var mc:MovieClip = new MovieClip();
addChild(mc);
mc.graphics.lineStyle(5, 0xFF0000, 1);
mc.graphics.moveTo(posX, posY - rad)
mc.i = -Math.PI / 2;
tweenToNext();
function tweenToNext(per:Number = 360):void {
degrees += 1;
if (mc.i <= (3 * Math.PI / 2) && degrees < per) {
var x:Number = posX + Math.cos(mc.i) * rad;
var y:Number = posY + Math.sin(mc.i) * rad;
mc.graphics.lineTo(x, y);
mc.i += Math.PI / 180;
TweenLite.to(mc, 0.001, {onComplete:tweenToNext});
}
}
I have tried Timer and setTimeout but these produce the same slow speed.
Flash application runs on frame-to-frame basis: frame render - script execution - frame render - script execution - frame render - script execution - and so on. That also means that whatever smallest delay you're putting there, the next call will not happen before next script execution phase, basically, next frame. Thus - guess what - your circle drawing takes 360 frames. 12 seconds if you have 30 FPS, for example.
If you want to make something synchronize with the real time, you need a different approach. I didn't check if this works, but I hope you'll get the idea and fix the mistakes if any.
var degrees:int;
var posX:int = 102;
var posY:int = 102;
var rad:int = 100;
var mc:MovieClip = new MovieClip;
addChild(mc);
mc.graphics.lineStyle(5, 0xFF0000, 1);
mc.graphics.moveTo(posX, posY + rad);
// Now, magic time.
// Save time since app start (in milliseconds).
var startTime:int = getTimer();
// 1000 milliseconds = 1 second.
var drawingTime:int = 1000;
// Store the maximum degree to draw.
var degreeLimit:int = 360;
// Call it every frame.
mc.addEventListener(Event.ENTER_FRAME, onDraw);
function onDraw(e:Event):void
{
// Now we need to check how much time passes since last frame
// and update the drawing accordingly.
var timeProgress:Number = (getTimer() - startTime) / drawingTime;
var drawingProgress:Number = degrees / degreeLimit;
// When the drawing progress catches the time progress
// the loop will end. It will resume on the next frame.
while (drawingProgress < timeProgress)
{
degrees += 1;
// It's better than a property on target canvas,
// which could be Sprite or Shape, they wouldn't take random fields.
var anAngle:Number = degrees * Math.PI / 180;
var tox:Number = posX + Math.cos(anAngle) * rad;
var toy:Number = posY + Math.sin(anAngle) * rad;
mc.graphics.lineTo(tox, toy);
// We should know when to stop it.
if (dergees >= degreeLimit)
{
mc.removeEventListener(Event.ENTER_FRAME);
return;
}
// Update the drawing progress.
drawingProgress:Number = degrees / degreeLimit;
}
}

Properly hovering over isometric tile sprite

I have four classes: Room, TileGrid, HoverTile, and Tile.
Room is composed of walls and a TileGrid. TileGrid is made out of Tile. Currently, I use this code to generate a TileGrid out of Tiles:
this.mapArray = [[1,1,1,1,1,1,1],
[1,1,1,1,1,1,1],
[1,1,1,1,1,1,1],
[1,1,1,1,1,1,1],
[1,1,1,1,1,1,1],
[1,1,1,1,1,1,1],
[1, 1, 1, 1, 1, 1, 1]];
this._mapHeight = this.mapArray.length;
this._mapWidth = this.mapArray[0].length;
this._tileHeight = 23;
this._tileWidth = 46;
var initialX:Number = 260;
var initialY:Number = 150;
for (var isoY:int = 0; isoY < mapArray.length; isoY++)
{
for (var isoX:int = 0; isoX < mapArray[isoY].length; isoX++)
{
if (isoX == 0 && isoY == 0)
{
var _tile:Tile = new Tile();
_tile.x = initialX;
_tile.y = initialY;
this.addChild(_tile);
}
if (this.mapArray[isoY][isoX] == 1)
{
var _tile:Tile = new Tile();
_tile.x = initialX - (isoX * 20) - (isoY * 20);
_tile.y = initialY - (isoX * 10) + (isoY * 10);
addChild(_tile);
_tile.addEventListener(MouseEvent.MOUSE_OVER, updateHover);
}
}
}
My current issue is that I want to add a white square around the tile that a mouse is hovering over. The code I used to use wasn't sufficient, because transparent parts of the Tile sprite are still counted as part of it. So even if I'm pointing at another Tile2 (which is next to Tile1), for example, if I'm not far enough onto Tile2, it'll highlight Tile1.
So, here's the current code I'm using:
public function updateHover(e:MouseEvent):void
{
var mX:int = e.stageX - (_tileWidth / 2);
var tPoint:Point = pointToXY(mX, e.stageY);
var isoX = tPoint.x;
var isoY = tPoint.y;
if (isoX >= 0 && isoY >= 0)
{
if (isoY < mapArray.length)
{
if (isoX < mapArray[0].length)
{
tPoint = xyToPoint(isoX, isoY);
_tileHover.x = tPoint.x;
_tileHover.y = tPoint.y;
_tileHover.visible = true;
return;
}
}
}
_tileHover.visible = false;
}
public function pointToXY(x:int, y:int):Point
{
x -= 260;
y -= 150;
var pRatio:int = (_tileWidth / 2) / (_tileHeight / 2);
var tX:int = (y + x / pRatio) * (pRatio / 2) / (_tileWidth / 2);
var tY:int = (y - x / pRatio) * (pRatio / 2) / (_tileWidth / 2);
return new Point(tX, tY);
}
public function xyToPoint(x:int, y:int):Point
{
x -= 1;
var worldPoint:Point = new Point(0, 0);
worldPoint.x = (x * (_tileWidth / 2)) - (y * (_tileWidth / 2));
worldPoint.y = (x * (_tileHeight / 2)) + (y * (_tileHeight / 2));
worldPoint.x = worldPoint.x + (_tileWidth / 2);
worldPoint.y = worldPoint.y + (_tileHeight / 2);
worldPoint.x += 260;
worldPoint.y += 150;
return worldPoint;
}
Sorry I have to post so many code blocks. Now, 260 and 150 are the default starting point for the entire room. That said, I'm really confused on how to get the last two functions in particular to work so that they'll give me the correct answer. This is what I expected from using this code:
That would be perfect. But, again, I don't know why the code isn't working. The sizes are all correct and I believe the offset is, too. So, I'm
First, you should add the listener to this, not to _tile, because then you are locked to stage coordinates to determine the tile that's selected, which is not good. Second, your listener should be against MouseEvent.MOUSE_MOVE event, not over, this way you'll constantly get updated mouse coords to properly move your rectangle over tiles. And you have a minor error out there, you have a (0,0) tile created two times, one being inactive.
for (var isoY:int = 0; isoY < mapArray.length; isoY++)
{
for (var isoX:int = 0; isoX < mapArray[isoY].length; isoX++)
{
if (this.mapArray[isoY][isoX] == 1)
{
var _tile:Tile = new Tile();
_tile.x = initialX - (isoX * 20) - (isoY * 20);
_tile.y = initialY - (isoX * 10) + (isoY * 10);
addChild(_tile);
}
}
}
this.addEventListener(MouseEvent.MOUSE_MOVE, updateHover);
Also, it'll be better that you'd store (x,y) pairs on the array (as tiles, most likely), so that your initial array of zeroes and ones would transform into an array of Tile objects. To do that, you first do this:
this.tileArray=[];
for (var i:int=0;i<this.mapArray.length;i++)
this.tileArray.push(new Array(this.mapArray[i].length));
This will create an array of nulls that matches your mapArray by dimensions, that will serve as placeholder for created Tile objects. After you do this, you call this.tileArray[isoY][isoX]=_tile; to place the newly created tile to its place. After that, you can rewrite your listener to this:
public function updateHover(e:MouseEvent):void
{
var p:Point=pointToXY(e.localX,e.localY);
_tileHover.visible = false; // hide hover for now
if ((p.y<0) || (p.y>=tileArray.length)) return; // range error on Y
if ((p.x<0)||(p.x>=tileArray[p.y].length)) return; // range error on X
if (!tileArray[p.y][p.x]) return; // no tile
var _tile:Tile=tileArray[p.y][p.x];
_tileHover.x=_tile.x;
_tileHover.y=_tile.y; // no need to convert xyToPoint() we have coords stored in tile
_tileHover.visible=true;
}

How do I increase enemy's speed every time level increases?

I have a very long code set up, and I know there should be an easier way, but I can't seem to find it. I want the enemies to increase speed every level by .5. How can I do this?
function makeEnemies():void
{
var chance:Number = Math.floor(Math.random() * 150);
if (chance <= + level)
{
tempEnemy = new Enemy();
tempEnemy.speed = 2
//Math.random(); gets a random number from 0.0-1.0
tempEnemy.x = Math.round(Math.random() * 1000);
addChild(tempEnemy);
enemies.push(tempEnemy);
if (level == 2)
{
tempEnemy.speed = 3
}
if (level == 3)
tempEnemy.speed = 4
}
}
}
You can try something like:
var enemyBaseSpeed:int = 2;
var speedLevelInc:Number = 0.5;
then later:
tempEnemy.speed = enemyBaseSpeed + ((level - 1) * speedLevelInc);
(Though you sample code shows the speed increasing by 1 per level)

Breakout with Flash: I need help to improve my Brick n Ball collision

I've been stuck on this problem for a very long time now, I've searched around alot and tried stuff, but nothing works. Some explanations are just very hard for me to understand as Im pretty new to programming overall and got alot to learn.
I have two problems
1: The ball wont collide with the bricks sometimes when the speed is too fast.
2: The ball is capable of hitting 2 bricks.
Both problems is related to the fact that 60 fps isnt enough for my type of collision detection to work properly.
I just need someone to explain in a simple way as possible what I need to do to make a collision detection that will prevent this from happen.
Here's my current collision code:
private function checkCollision(): void {
grdx = Math.floor((ball.x) / 28);
grdy = Math.floor((ball.y) / 14);
ngrdx = Math.floor((ball.x + dx) / 28);
ngrdy = Math.floor((ball.y + dy) / 14);
var flipX: Boolean = false;
var flipY: Boolean = false;
if ((grdy <= level.length - 1) &&
(ngrdy <= level.length - 1) &&
(grdy >= 0 && ngrdy >= 0)) {
if (testBlock(grdx, ngrdy)) {
flipY = true;
paddleFlag = 1;
}
if (testBlock(ngrdx, grdy)) {
flipX = true;
paddleFlag = 1;
}
if (testBlock(ngrdx, ngrdy)) {
flipX = true;
flipY = true;
paddleFlag = 1;
}
dx *= flipX ? -1 : 1;
dy *= flipY ? -1 : 1;
}
}
private function testBlock(xPos: int, yPos: int): Boolean {
if (level[yPos][xPos] > 0 && level[yPos][xPos] != 13) {
trace("hit on X,Y");
level[yPos][xPos] = 0;
breakBlock("Block_" + yPos + "_" + xPos);
trace("Block: " + totalBreaks + " / " + totalBlocks);
return true;
}
return false;
}
private function breakBlock(blockName: String): void {
if (this.getChildByName(blockName)) {
this.removeChild(this.getChildByName(blockName));
totalBreaks++;
}
}
Thank you and sorry for my bad english, its not my motherlanguage.
One solution is to move the ball in smaller iterations, multiple times in a given frame.
For example, and I am giving this solution assuming that you are moving the ball based on the time elapsed from the last frame.
Suppose that 30 milliseconds have elapsed since the last frame update. In that case you would update the movement/collision twice in that frame using 15 millisecond as your time elapsed.
The higher resolution of collision you want, the more iterations you would do.
Here's an example :
// class declarations
var lastFrame:Number;
var iterationsPerFrame:int;
function startGame():void
{
// lets specify 3 updates per frame
iterationsPerFrame = 3;
// save initial time
lastFrame = getTimer();
// create your listener
addEventListener(Event.ENTER_FRAME, update);
}
function update(e:Event):void
{
var currentFrame:Number = getTimer();
var deltaTime:Number = (currentFrame - lastFrame)/1000;
var iterationDelta:Number = deltaTime/iterationsPerFrame;
for (var index:int = 0;index < iterationsPerFrame;index++)
{
// I'm assuming dx,dy are the velocity of the ball, in pixels per second
ball.x += dx * iterationDelta;
ball.y += dy * iterationDelta;
// check collision
}
// set lastFrame to the currentFrame time, preparing for next frame
lastFrame = currentFrame;
// after this, your frame is going to render
}
You could work out how far the ball travels each frame (A) based on its speed, how far the ball is from the paddle (B) and if A > B manually trigger a collision that frame.
You're essentially checking every bricks X and Y coordinate to the balls X and Y coordinate, so if the bricks are stored in an array this becomes: Sqrt( Sqrd(p2.x - p1.x) + Sqrd(p2.y - p1.y))
for(var i=0; i<brickArray.length; i++)
{
var distance:Number = Math.sqrt((brickArray[i].x - ball.x) * (brickArray[i].x - ball.x) +
(brickArray[i].y - ball.y) * (brickArray[i].y - ball.y));
}
This is a very good tutorial on high speed collison detection:
http://www.newgrounds.com/bbs/topic/1072673

Playing a random frame inside MovieClip with AS3

I have a movie clip (goalkeeper) with different positions in different frames (inside), I would like to play a random frame after executing a function to make the goalkeeper move to a determinate position, there are 6 frames with 6 different positions so I need to play 1 position randomly, this is the code that should go to the random number after ball is kicked:
function moveBall()
{
var targetX:Number = mouseX;
var targetY:Number = mouseY;
var angle = Math.atan2(targetY,targetX);
ball.x = mouseX + Math.cos(angle);
ball.y = mouseY + Math.sin(angle) ;
ballRotation = true;
if (ballRotation==true)
{
goalkeeper_mc.gotoAndStop( Random Frame);//Here is when I need to go and play the random frame everytime function is executed
}
Thanks a lot for your help guys, sorry for bothering again, I searched the web for some examples but I found many of them really complicated for a newbie like me.
refer a following code.
you must randomize from 1 frame to last Frame.
Math.random () of the range is greater than 0 and less than 1(floating-value). by use it implements available.
function moveBall()
{
var targetX:Number = mouseX;
var targetY:Number = mouseY;
var angle = Math.atan2(targetY,targetX);
ball.x = mouseX + Math.cos(angle);
ball.y = mouseY + Math.sin(angle) ;
ballRotation = true;
if (ballRotation==true)
{
goalkeeper_mc.gotoAndStop(int(Math.random * (goalkeeper_mc.totalFrames)+1));
}
}
goalkeeper_mc.gotoAndStop(1 + Math.floor(Math.random() * goalkeeper_mc.totalFrames));