Action Script 3. Spawn objects in different time - actionscript-3

I'm creating game where falling 4 different objects from the sky and need to destroy them by clicking mouse button. My problem is that all 4 objects spawns at the same time. I need to make that randomly spawned all 4, but not in the same time and after player have 200 points I need to make that spawned and falled more objects. (I have working counter which counting points).
And one more thing if you know how to make that objects not spawned on one other.
I mean:
Bad spawn.
Here is my constant vars:
public static const GRAVITY:Number = 3;
public static const HIT_TOLERANCE:Number = 50;
//Powerup
public static const APPLE_END_Y:Number = 640;
public static const APPLE_SPAWN_CHANCE:Number = 0.02; //per frame per second
public static const APPLE_START_Y:Number = 110;
public static const APPLE_SPAWN_START_X:Number = 50;
public static const APPLE_SPAWN_END_X:Number = 500;
//Scoring
public static const PLAYER_START_SCORE:Number = 0;
public static const SCORE_PER_APPLE:Number = 10;
Here is part of my code:
public function startGame()
{
speed = C.PLAYER_SPEED;
gravity = C.GRAVITY;
score = C.PLAYER_START_SCORE;
randomChance = C.APPLE_SPAWN_CHANCE;
tol = C.HIT_TOLERANCE;
apples = new Array();
mcGameStage.addEventListener(Event.ENTER_FRAME,update);
}
private function update(evt:Event)
{
//Spawn new apples
if (Math.random() < randomChance)
{
//spawn x coordinates
var newPirmas = new Pirmas();
newPirmas.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
var newAntras = new Antras();
newAntras.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
var newTrecias = new Trecias();
newTrecias.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
var newApple = new Apple();
newApple.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
//spawn y coordinates
newPirmas.y = C.APPLE_START_Y;
newAntras.y = C.APPLE_START_Y;
newTrecias.y = C.APPLE_START_Y;
newApple.y = C.APPLE_START_Y;
apples.push(newPirmas);
apples.push(newAntras);
apples.push(newTrecias);
apples.push(newApple);
newPirmas.addEventListener(MouseEvent.CLICK, onClick);
newAntras.addEventListener(MouseEvent.CLICK, onClick);
newTrecias.addEventListener(MouseEvent.CLICK, onClick);
newApple.addEventListener(MouseEvent.CLICK, onClick);
mcGameStage.addChildAt(newPirmas,0);
mcGameStage.addChildAt(newAntras,0);
mcGameStage.addChildAt(newTrecias,0);
mcGameStage.addChildAt(newApple,0);
}
//Move Apples
for (var i = apples.length-1; i >= 0; i--)
{
apples[i].y += gravity;
if (apples[i].y > C.APPLE_END_Y)
{
mcGameStage.removeChild(apples[i]);
apples.splice(i,1);
m_iLives--;
if (!m_iLives)
{
trace("Game Over");
// newApple.removeEventListener(MouseEvent.CLICK, onClick);
break;
}
}
}
txtScore.text = String(score);
}
function onClick(evt:MouseEvent):void{
var apples = evt.target;
apples.visible = false;
apples = tol;
score += C.SCORE_PER_APPLE;
}
}

public function startGame()
{
speed = C.PLAYER_SPEED;
gravity = C.GRAVITY;
score = C.PLAYER_START_SCORE;
randomChance = C.APPLE_SPAWN_CHANCE;
tol = C.HIT_TOLERANCE;
apples = [];
itemsToSpawn = [];
mcGameStage.addEventListener(Event.ENTER_FRAME,update);
nextSpawn:Number = 0;
}
private function update(evt:Event)
{
//Spawn new apples
if (Math.random() < randomChance)
{
//spawn x coordinates
var newPirmas = new Pirmas();
newPirmas.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
var newAntras = new Antras();
newAntras.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
var newTrecias = new Trecias();
newTrecias.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
var newApple = new Apple();
newApple.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
//spawn y coordinates
newPirmas.y = C.APPLE_START_Y;
newAntras.y = C.APPLE_START_Y;
newTrecias.y = C.APPLE_START_Y;
newApple.y = C.APPLE_START_Y;
newPirmas.addEventListener(MouseEvent.CLICK, onClick);
newAntras.addEventListener(MouseEvent.CLICK, onClick);
newTrecias.addEventListener(MouseEvent.CLICK, onClick);
newApple.addEventListener(MouseEvent.CLICK, onClick);
//add items to itemsToAdd
itemsToAdd.push(newPirmas, newAntras, newTrecias, newApple);
}
//Move Apples
for (var i = apples.length-1; i >= 0; i--)
{
apples[i].y += gravity;
if (apples[i].y > C.APPLE_END_Y)
{
mcGameStage.removeChild(apples[i]);
apples.splice(i,1);
m_iLives--;
if (!m_iLives)
{
trace("Game Over");
// newApple.removeEventListener(MouseEvent.CLICK, onClick);
break;
}
}
}
txtScore.text = String(score);
if( itemsToSpawn.length > 0 && getTimeout() > nextSpawn )
{
var item:DisplayObject = itemsToAdd.shift();
apples.push(item);
mcGameStage.addChild(item);
nextSpawn = getTimeout() + Math.random() * 4000;
}
}
function onClick(event:MouseEvent):void
{
var apples = event.currentTarget;
apples.visible = false;
apples = tol;
score += C.SCORE_PER_APPLE;
if(score % 100 == 0)
{
gravity += 10;
}
}

In your update code, you're checking a single time for a random value to be less than randomChance, and when it is, you spawn 4 apples.
If you want them to spawn at different times, you would call them one at a time. I would make a function to create a randomly placed apple, and call that whenever your if statement is satisfied.
Eg:
private function update(evt:Event){
if(Math.random() < randomValue){
createApple();
}
Where createApple() would create a new apple, position it, add it to the array, and add it to the stage.
If you're trying to create a different apple each time, you can put the different types in an array and iterate through it as you create new apples.
EG.
private function createApple(){
...
var newApple = appleToSpawn[currentApple]
...
}
Where appleToSpawn is an array of apple objects, and currentApple is an index of which apple you're currently on.
Alternatively, you could do a series of comparisons to a random number, and spawn a different apple depending on which condition is satisfied.
As for making sure they don't overlap, you can keep a history of their spawn points, and change how you get their random X value. Just iterate through the array of previous X values, and make sure the new one isn't within (oldX + (width/2)).
Now for spawning more than 4 as you get more points, just change your randomChance to a bigger number as you go. If it's a bigger number, you'll satisfy your conditional statement more often, therefor spawning more apples.

Related

Adding another Movie Clip into another Frame

I am attempting to add a new movie clip into the next frame of my shooter game.
I am using Actionscript 3.0
To give a basis of what I need help with for my assessment. When the score =50, switch to the next frame. And this is where I would like to add a new type of movie clip for the user to shoot!
Here is the code I have so far.
FRAME 1
//Tate's open screen
stop(); //makes the screen wait for events
paraBtn.addEventListener(MouseEvent.CLICK, playClicked); //this line is making your button an mouse click event
function playClicked(evt: MouseEvent): void { // now we are calling the event from this function and telling it to go to the next frame we labelled play
gotoAndStop("frame2");
// All rights of this music goes towards the makers of the game "Risk of Rain" which was made by Hapoo Games
}
FRAME 2 (Where the game actually starts)
stop();
// This plays the sound when left click is used
var spitSound: Sound = new Sound();
spitSound.load(new URLRequest("gunSound.mp3"));
//This plays the gameover sound when your lives reach 0
var overSound: Sound = new Sound();
overSound.load(new URLRequest("Gameover.mp3"));
//This plays the sound when you are hit
var etSound: Sound = new Sound();
etSound.load(new URLRequest("Urgh.mp3"));
//This sets the lives and points.
stage.addEventListener(MouseEvent.MOUSE_MOVE, aimTurret);
var points: Number = 0;
var lives: Number = 3;
var target: MovieClip;
var _health: uint = 100;
initialiseCursor();
//This variable stops the multiple errors with the move objects and bullets and range to stop compiling.
var Gameover: Boolean = false;
//This aims the turrent to where you mouse is on the screen
function aimTurret(evt: Event): void {
if (Gameover == false) {
gun.rotation = getAngle(gun.x, gun.y, mouseX, mouseY);
var distance: Number = getDistance(gun.x, gun.y, mouseX, mouseY);
var adjDistance: Number = distance / 12 - 7;
}
}
function getAngle(x1: Number, y1: Number, x2: Number, y2: Number): Number {
var radians: Number = Math.atan2(y2 - y1, x2 - x1);
return rad2deg(radians);
}
function getDistance(x1: Number, y1: Number, x2: Number, y2: Number): Number {
var dx: Number = x2 - x1;
var dy: Number = y2 - y1;
return Math.sqrt(dx * dx + dy * dy);
}
function rad2deg(rad: Number): Number {
return rad * (180 / Math.PI);
}
//Starts lives and shows text next to the numbers
function initialiseCursor(): void {
Mouse.hide();
target = new Target();
target.x = mouseX;
target.y = mouseY;
target.mouseEnabled = false;
addChild(target);
stage.addEventListener(MouseEvent.MOUSE_MOVE, targetMove);
stage.addEventListener(MouseEvent.MOUSE_DOWN, targetDown);
stage.addEventListener(MouseEvent.MOUSE_UP, targetUp);
livesdisplay.text = String(lives) + " Lives Left";
pointsdisplay.text = String(points) + " Points";
}
function targetMove(evt: MouseEvent): void {
target.x = this.mouseX;
target.y = this.mouseY;
}
function targetDown(evt: MouseEvent): void {
target.gotoAndStop(2);
}
function targetUp(evt: MouseEvent): void {
target.gotoAndStop(1);
}
//Starts bullets and speed of bullets, also addding new arrays for baddies
var gunLength: uint = 90;
var bullets: Array = new Array();
var bulletSpeed: uint = 20;
var baddies: Array = new Array();
stage.addEventListener(MouseEvent.MOUSE_DOWN, fireGun);
function fireGun(evt: MouseEvent) {
if (Gameover == false) {
var bullet: Bullet = new Bullet();
bullet.rotation = gun.rotation;
bullet.x = gun.x + Math.cos(deg2rad(gun.rotation)) * gunLength;
bullet.y = gun.y + Math.sin(deg2rad(gun.rotation)) * gunLength;
addChild(bullet);
bullets.push(bullet);
spitSound.play();
}
}
function deg2rad(deg: Number): Number {
return deg * (Math.PI / 180);
}
stage.addEventListener(Event.ENTER_FRAME, moveObjects);
function moveObjects(evt: Event): void {
if (Gameover == false) {
moveBullets();
moveBaddies();
}
}
function moveBullets(): void {
for (var i: int = 0; i < bullets.length; i++) {
var dx = Math.cos(deg2rad(bullets[i].rotation)) * bulletSpeed;
var dy = Math.sin(deg2rad(bullets[i].rotation)) * bulletSpeed;
bullets[i].x += dx;
bullets[i].y += dy;
if (bullets[i].x < -bullets[i].width || bullets[i].x > stage.stageWidth + bullets[i].width || bullets[i].y < -bullets[i].width || bullets[i].y > stage.stageHeight + bullets[i].width) {
removeChild(bullets[i]);
bullets.splice(i, 1);
}
}
}
// This is the start of the timer
var timer: Timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER, addBaddie);
timer.start();
// Adding army men on a timer and only from the top side
function addBaddie(evt: TimerEvent): void {
var baddie: Baddie = new Baddie();
var side: Number = Math.ceil(Math.random() * 1);
if (side == 1) {
baddie.x = Math.random() * stage.stageWidth;
baddie.y = -baddie.height;
}
baddie.angle = getAngle(baddie.x, baddie.y, gun.x, gun.y);
baddie.speed = 7;
addChild(baddie);
baddies.push(baddie);
}
function moveBaddies(): void {
for (var i: int = 0; i < baddies.length; i++) {
var dx = Math.cos(deg2rad(baddies[i].angle)) * baddies[i].speed;
var dy = Math.sin(deg2rad(baddies[i].angle)) * baddies[i].speed;
baddies[i].x += dx;
baddies[i].y += dy;
if (baddies[i].hitTestPoint(gun.x, gun.y, true)) {
removeChild(baddies[i]);
baddies.splice(i, 1);
loseLife();
//If baddie was removed then we don’t check for bullet hits
} else {
checkForHit(baddies[i]);
}
}
}
function checkForHit(baddie: Baddie): void {
for (var i: int = 0; i < bullets.length; i++) {
if (baddie.hitTestPoint(bullets[i].x, bullets[i].y, true)) {
removeChild(baddie);
points++;
if (points == 50) {
gotoAndStop("frame3")
}
pointsdisplay.text = String(points) + " Points";
baddies.splice(baddies.indexOf(baddie), 1);
}
}
}
// Keeping track of lost lives and when hitting 0 doing to frame four, also displaying "Lose life!"
function loseLife(): void {
etSound.play();
lives--;
if (lives == 0) {
Gameover = true;
overSound.play();
gotoAndStop("frame4")
}
livesdisplay.text = String(lives) + " Lives Left";
trace("Lose Life!");
}
FRAME 3 (This is where I need help, to add another movie clip) (I have made one for the frame named, "BaddieRed" With the Linkage being "Baddiered"
stop();
// The code from frame2 carries over and works the same in this frame
FRAME 4 (This is the screen where it's gameover)
stop();
timer.stop();
// User need to close by pressing the close button
//And restart the game manually
Is this what you're trying to achieve? Something like...
function addBaddie(evt: TimerEvent): void
{
var baddie : MovieClip;
if (points < 50) { var bad1: Baddie = new Baddie(); baddie = bad1; }
if (points >= 50) { var bad2 : Baddiered = new Baddiered(); baddie = bad2; }
var side: Number = Math.ceil(Math.random() * 1);
if (side == 1)
{
baddie.x = Math.random() * stage.stageWidth;
baddie.y -= baddie.height;
}
baddie.angle = getAngle(baddie.x, baddie.y, gun.x, gun.y);
baddie.speed = 7;
addChild(baddie);
baddies.push(baddie);
}

Action Script 3. How to remember last object x coordinates

I'm creating a flash game where objects are falling from the sky and the player needs to destroy them by clicking on them. But I have a problem, sometimes they spawning one on top of each other.
Here is an example what I mean:
Objects should be spawned near other, but not one on other.
Here is my constant vars:
public static const GRAVITY:Number = 3;
public static const HIT_TOLERANCE:Number = 50;
//Powerup
public static const APPLE_END_Y:Number = 640;
public static const APPLE_SPAWN_CHANCE:Number = 0.02; //per frame per second
public static const APPLE_START_Y:Number = 110;
public static const APPLE_SPAWN_START_X:Number = 50;
public static const APPLE_SPAWN_END_X:Number = 500;
//Scoring
public static const PLAYER_START_SCORE:Number = 0;
public static const SCORE_PER_APPLE:Number = 10;
Here is part of code where objects spawning:
private function update(evt:Event)
{
//Spawn new apples
if (Math.random() < randomChance)
{
//spawn x coordinates
var newPirmas = new Pirmas();
newPirmas.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
var newAntras = new Antras();
newAntras.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
var newTrecias = new Trecias();
newTrecias.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
var newApple = new Apple();
newApple.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
//spawn y coordinates
newPirmas.y = C.APPLE_START_Y;
newAntras.y = C.APPLE_START_Y;
newTrecias.y = C.APPLE_START_Y;
newApple.y = C.APPLE_START_Y;
newPirmas.addEventListener(MouseEvent.CLICK, onClick);
newAntras.addEventListener(MouseEvent.CLICK, onClick);
newTrecias.addEventListener(MouseEvent.CLICK, onClick);
newApple.addEventListener(MouseEvent.CLICK, onClick);
itemsToSpawn.push(newPirmas, newAntras, newTrecias, newApple);
}
}
As someone said: As for making sure they don't overlap, you can keep a history of their spawn points, and change how you get their random X value. Just iterate through the array of previous X values, and make sure the new one isn't within (oldX + (width/2)).
But I can't make It successfully, could you help me with keeping history of their spawn points? Thank you very much.
var t:Array = [];
t[0] = [APPLE_SPAWN_START_X, APPLE_SPAWN_END_X + APPLE_WIDTH/2];
t will keep the available intervals the you can generate new apple.
In the start time, there is no apple, and the t has only one interval, the starX of the interval is APPLE_SPAWN_START_X, the endX of the interval is APPLE_SPAWN_END_X + APP_WIDTH/2.
where you want to generate a new apple, you would find a availble interval in t, if we find the interval as mInterval(the interval could put in the apple, means endX - starX >= APPLE_WIDTH), then we could generate your new apple.
We just need to change the lines in you update function like
newPirmas.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
Instead
newPirmas.x = mInterval[0] + Math.random()*APPLE_WIDTH;
When we set newPirmas.x, we have break the mInterval and generate two new interval,
the values are [mInterval[0],newPirmas.x] and []newPirmas.x + APPLE_WIDTH, mInterval[0]],
so we need to delete the mInterval in t and put the two new intervals into t.
/**
*
* #return index of available interval in target array
*/
public static function findAvailInterval(target:Array, appleWidth:int):int {
if (target == null || target.length == 0) {
return -1;
}
var endX:int = 0;
var startX:int = 0;
var length:int = target.length;
for (var i:int = 0; i < length; i++) {
var temp:Array = target[i] as Array;
if (temp == null || temp.length < 2) {
return -1;
}
startX = temp[0];
endX = temp[1];
var intervalWidth:int = endX - startX;//the interval width
if (intervalWidth >= appleWidth) {//find an available one
return i;
}
}
return -1;
}
public static function breakInterval(target:Array, appleWidth:int, index:int):int {
var temp:Array = target[index];
var startX:int = temp[0];
var endX:int = temp[1];
var width:int = endX - startX;
var availableNewXRange:int = width - appleWidth;//the apple‘s max x, and the min x is startX
//random a position
var appleX:int = startX + availableNewXRange*Math.random();
var leftInterval:Array = [startX, appleX];//the left interval of apple
var rightInterval:Array = [appleX+appleWidth, endX];//the right interval of apple
//delete temp
target.splice(index, 1);
if (isAvailableInterval(leftInterval, appleWidth)) {
target.push(leftInterval);
}
if (isAvailableInterval(rightInterval, appleWidth)) {
target.push(rightInterval);
} else {
trace("vvv");
}
return appleX;
}
private static function isAvailableInterval(interval:Array, appleWidth:int):Boolean {
if (interval == null || interval.length < 2) {
return false;
}
return (interval[1] - interval[0]) >= appleWidth;
}
Put the three functions into a class A
var target:Array = [[0, 1000]];
var appWidth:int = 80;
for (var i:int = 0; i < 4; i++) {
var index:int = A.findAvailInterval(target, appWidth);
if (index != -1) {
var interval:Array = target[index];
RR.breakInterval(target, appWidth, index);
trace(interval);
}
}

Action Script 3. Delete object when mouse clicked

I'm creating flash game, Idea is falling objects (in this case apples) from the sky and player need to click on apples, after apple is clicked It must be deleted and Score updated by 10 points.
Here is my part of code where apples is spawning:
public function startGame()
{
speed = C.PLAYER_SPEED;
gravity = C.GRAVITY;
score = C.PLAYER_START_SCORE;
randomChance = C.APPLE_SPAWN_CHANCE;
apples = new Array();
mcGameStage.addEventListener(Event.ENTER_FRAME,update);
}
private function update(evt:Event)
{
//Spawn new apples
if (Math.random() < randomChance)
{
var newApple = new Apple();
newApple.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
newApple.y = C.APPLE_START_Y;
apples.push(newApple);
mcGameStage.addChildAt(newApple,0);
}
//Move Apples
for (var i = apples.length-1; i >= 0; i--)
{
apples[i].y += gravity;
if (apples[i].y > C.APPLE_END_Y)
{
mcGameStage.removeChild(apples[i]);
apples.splice(i,1);
}
}
//txtScore.text = String(score);
}
}
And here is code which should delete apples by mouse clicked. But It doesn't work, I don't have any errors, just not deleting apples. Could you help me please?
function onClick(evt:MouseEvent):void{
var apples = evt.target;
for (var iz = apples.length-1; iz >= 0; iz--)
{
//Register hit
score += C.SCORE_PER_APPLE;
mcGameStage.removeChild(apples[iz]);
apples.splice(iz,1);
}
}
UPDATE
So my code now looks like:
public function startGame()
{
speed = C.PLAYER_SPEED;
gravity = C.GRAVITY;
score = C.PLAYER_START_SCORE;
randomChance = C.APPLE_SPAWN_CHANCE;
apples = new Array();
mcGameStage.addEventListener(Event.ENTER_FRAME,update);
}
private function update(evt:Event)
{
//Spawn new apples
if (Math.random() < randomChance)
{
var newApple = new Apple();
newApple.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
newApple.y = C.APPLE_START_Y;
apples.push(newApple);
newApple.addEventListener(MouseEvent.CLICK, onClick);
mcGameStage.addChildAt(newApple,0);
}
//Move Apples
for (var i = apples.length-1; i >= 0; i--)
{
apples[i].y += gravity;
if (apples[i].y > C.APPLE_END_Y)
{
mcGameStage.removeChild(apples[i]);
apples.splice(i,1);
}
}
txtScore.text = String(score);
}
function onClick(evt:MouseEvent):void{
var apples = evt.target;
apples.visible = false;
//mcGameStage.removeChild(apples);
score += C.SCORE_PER_APPLE;
}
}
}
I use this apples.visible = false; instead mcGameStage.removeChild(apples); and It's all right.
Just I misunderstood why my score not updating? Always show 0.
And sometimes I can't set apples invisible by 1 click If it is click on top of apple nothing happens, I need to click on apple's center to hide It, why I have this problem?
If you are serious about game development, you should think about code bloat. In your case, you don't need any apples array - your display list, courtesy Flash Player, is already able to contain the apples in a sorted linked list structure - much more efficient for the kind use you intend for it - deleting and adding apples. If you dedicate a container sprite just for containing apples, you get two benefits: 1) you get a free display list of apples and 2) if you register a mouse click event listener for this sprite (which contains only apples), then every click is on an apple and event.target will reflect it.
Review the altered code carefully:
public function startGame()
{
speed = C.PLAYER_SPEED;
gravity = C.GRAVITY;
score = C.PLAYER_START_SCORE;
randomChance = C.APPLE_SPAWN_CHANCE;
mcApples = new Sprite();
mcApples.addEventListener(MouseEvent.CLICK, onClickApple);
mcGameStage.addChild(mcApples);
mcGameStage.addEventListener(Event.ENTER_FRAME, update);
}
private function update(evt:Event)
{
//Spawn new apple
if(Math.random() < randomChance)
{
var newApple = new Apple();
newApple.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
newApple.y = C.APPLE_START_Y;
mcApples.addChild(newApple);
}
//Move Apples
for (var i = 0; i < mcApples.numChildren;)
{
var apple = mcApples.getChildAt(i);
apple.y += gravity;
if(apple.y > C.APPLE_END_Y)
{
apple.parent.removeChild(apple);
continue;
}
i++;
}
}
function onClickApple(event: MouseEvent):void
{
var apple : Apple = event.target;
apple.parent.removeChild(apple);
score += C.SCORE_PER_APPLE;
}
The important changes and their effects are thus:
Dedicated sprite mcApples where apples are added and removed from.
No need for an array of apples, Flash Player keeps track of apples in mcApples container.
Mouse clicking listener setup guarantees any click is on an apple.
So, no splicing of arrays required and no need for explicit function references in Apple class or adding event listener for each new apple.
As an extra piece of advice, you should be careful binding your logic to enter frame events - the faster the frame rate, the faster the call frequency - usually no problem, but sometimes not what you want. I would bind the update call to a timer event instead ;-)
private function update(evt:Event)
{
//Spawn new apples
if (Math.random() < randomChance)
{
var newApple = new Apple(appleClick);
newApple.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
newApple.y = C.APPLE_START_Y;
apples.push(newApple);
mcGameStage.addChildAt(newApple,0);
}
//Move Apples
for (var i = apples.length-1; i >= 0; i--)
{
apples[i].y += gravity;
if (apples[i].y > C.APPLE_END_Y)
{
mcGameStage.removeChild(apples[i]);
apples[iz].destruct();
apples.splice(i,1);
}
}
//txtScore.text = String(score);
}
function appleClick(pApple:Apple):void{
for (var iz = apples.length-1; iz >= 0; iz--)
{
if (apples[iz] == pApple)
{
//Register hit
score += C.SCORE_PER_APPLE;
mcGameStage.removeChild(apples[iz]);
apples[iz].destruct();
apples.splice(iz,1);
break;
}
}
}
....
public class Apple extends Group or something
{
private var m_fCallback:Function;
public function Apple(pCallback:Function):void
{
addEventListener(MouseEvent.CLICK, onClick);
m_fCallback = pCallback;
}
private function destruct():void
{
removeEventListener(MouseEvent.CLICK, onClick);
}
private function onClick(pEvent:MouseEvent):void
{
m_fCallback(this);
}
}
I do not see any event listener added for onClick(). Be sure to check that your event listener is added, and put a trace or an alert in your onClick() function so that you can confirm that the code is actually reached.

catcher game lives won't update as3.0

I am trying to create a simple catcher game. I have the basic structure/logic figured out but I am facing some problems. For some reason the lives are not updating as I want them to. The only time they actually do work is when a "good" crane exits the screen at the top, then they decrease by one. But other than that (catch a "bad" crane or catch a "plus" crane) is not decreasing or increasing it by one. Similarly, the score seems to work for the "good" crane, adding the amount of score I specify, but not for the "bad" or the "plus" cranes.
What am I missing? Help!
package
{
import flash.display.*;
import flash.events.*;
import flash.text.*;
import flash.utils.*;
public class CatchingCranes extends MovieClip
{
//Define the variables
var catcher:CloudCatcher;
var nextCrane:Timer;
var objects:Array = new Array();
var score:int = 0;
var timer:Number;
var maxCount:Number = 60;
var totalLives:int = 5;
var CirclesArray:Array = [];
var spacer:int = 5;
var startPosition:int = 415;
var speed:Number = -7.0;
public function CatchingCranes()
{
createTimer();
createCatcher();
setNextCrane();
progressLevels();
addEventListener(Event.ENTER_FRAME, moveCranes);
}
//Function to indicate level progression
public function progressLevels()
{
status_mc.status_txt.text = "LEVEL ONE";
status_mc.instructions_txt.text = "COLLECT AT LEAST 500 POINTS";
if (score == 500)
{
status_mc.status_txt.text = "LEVEL TWO";
status_mc.instructions_txt.text = "COLLECT AT LEAST 750 POINTS";
goToLevelTwo();
}
if (score == 750)
{
status_mc.status_txt.text = "LEVEL THREE";
status_mc.instructions_txt.text = "COLLECT AT LEAST 1000 POINTS";
goToLevelThree();
}
if (score == 1000)
{
status_mc.status_txt.text = "CONGRATULATIONS";
status_mc.instructions_txt.text = "YOU NOW HAVE ONE WISH TO MAKE";
goToWin();
}
if (totalLives == 0)
{
status_mc.status_txt.text = "GAME OVER";
status_mc.instructions_txt.text = "CLICK TO TRY AGAIN";
goToLoose();
}
}
//Function to create a timer
public function createTimer()
{
var myTimer:Timer = new Timer(1000,maxCount);
myTimer.addEventListener(TimerEvent.TIMER, countdown);
myTimer.start();
function countdown(event:TimerEvent):void
{
timer = (maxCount)-myTimer.currentCount;
timer_txt.text = "TIME LEFT: " + String(timer);
if (timer <= 0)
{
trace("Time's Up");
myTimer.removeEventListener(TimerEvent.TIMER, countdown);
}
}
}
//Function to create the catcher
public function createCatcher()
{
catcher = new CloudCatcher();
catcher.y = 50;
catcher.x = 350;
addChild(catcher);
}
//Function to initiate the next crane production
public function setNextCrane()
{
nextCrane = new Timer(750+Math.random()*1000,1);
nextCrane.addEventListener(TimerEvent.TIMER_COMPLETE, newCrane);
nextCrane.start();
}
//Function to create a new crane
public function newCrane(event:Event)
{
//Array definition holding different kinds of cranes
var goodCranes:Array = ["ColorCrane1","ColorCrane2","ColorCrane3","ColorCrane4","ColorCrane5"];
var evilCranes:Array = ["EvilCrane"];
var silverCranes:Array = ["SilverCrane"];
var goldCranes:Array = ["GoldCrane"];
//Create a random number and check whether or not it is less than 0.9 (90 percent probability)
if (Math.random() < 0.9)
{
//Create good cranes
var r:int = Math.floor(Math.random() * goodCranes.length);
var classRef:Class = getDefinitionByName(goodCranes[r]) as Class;
var newCrane:MovieClip = new classRef();
newCrane.typestr = "good";
}
else
{
//Create a random number and check whether or not it is more than 0.9 (10 percent probability)
//Check to see if the current lives count is less than or equal to four, if it is
if (totalLives <= 4)
{
//Create cranes that provide user with an additional life
var p:int = Math.floor(Math.random() * silverCranes.length);
classRef = getDefinitionByName(silverCranes[p]) as Class;
newCrane = new classRef();
newCrane.typstr = "plus";
//Create cranes that are evil
var s:int = Math.floor(Math.random() * evilCranes.length);
classRef = getDefinitionByName(evilCranes[s]) as Class;
newCrane = new classRef();
newCrane.typstr = "bad";
}
else
{
//If lives are equal to five, only create the evil cranes
r = Math.floor(Math.random() * evilCranes.length);
classRef = getDefinitionByName(evilCranes[r]) as Class;
newCrane = new classRef();
newCrane.typstr = "bad";
}
}
//Specify the x and y location of the cranes
newCrane.x = Math.random() * 700;
newCrane.y = 500;
//Add crane
addChildAt(newCrane, 0);
objects.push(newCrane);
setNextCrane();
}
//Function to move the cranes up the stage
public function moveCranes(event:Event)
{
for (var i:int = objects.length-1; i>=0; i--)
{
//Make the catcher follow the position of the mouse
catcher.x = mouseX;
//Specify the crane's speed
objects[i].y += speed;
//If the object exits the top stage boundaries
if (objects[i].y < 0)
{
//Remove the child and take it out of the array
removeChild(objects[i]);
objects.splice(i,1);
//If that object is good
if (objects[i].typestr == "good")
{
//Remove one life from the user
totalLives = totalLives - 1;
trace(totalLives);
}
}
//Check to see if the crane collides with the cloud, if it does
if (objects[i].hitTestObject(catcher))
{
//And the crane is good
if (objects[i].typestr == "good")
{
//Add 25 to the score
score += 25;
}
//And the crane adds a life
if (objects[i].typestr == "plus")
{
//Add 10 to the score and increase lives by one
score += 10;
totalLives = totalLives + 1;
}
//And the crane is evil
if (objects[i].typestr == "bad")
{
//Take out 5 from the score and remove a life
score -= 5;
totalLives = totalLives - 1;
}
//If the score is less than zero, take it back to zero
if (score < 0)
{
score = 0;
}
//Remove the cranes and splice them from the array
removeChild(objects[i]);
objects.splice(i,1);
}
}
//Update the score display text and the lives with the correct values
score_display.text = "Score = " + score;
lives_txt.text = "Lives: " + totalLives;
}
//Functions to specify next level options and win/loose scenarios
function goToLevelTwo():void
{
}
function goToLevelThree():void
{
}
function goToWin():void
{
}
function goToLoose():void
{
}
}
}

Collision detection and clipping issues in AS3

I've recently started putting together a little physics simulation from scratch, something I've never tried before, and I've run into an issue regarding the interaction between the collision of the objects I have on stage, and what I think is my constant gravity. I'm not sure if 200 lines of code is too large for here, but this is what I have.
package {
import flash.events.*;
import flash.display.*;
import flash.geom.Rectangle;
[SWF (width="1500", height="1000", frameRate="24")]
public class ElasticityV2 extends MovieClip{
/* Gravity is 9.8 m/s2, which for flash, since it's being applied every frame, needs to be
divided out by the frame rate as to not have super fast acceleration. GravMulti is to balance
out gravity's speed, as it seemed a little slow after the framerate division. Resistance is acting
like friction for now, and slows down the objects in the air and on the ground at the same rate.
Elasticity is how bouncy each object is and how the force it recieves is applied*/
public var gravMulti:Number = 5;
public var gravity:Number = gravMulti *(9.8/stage.frameRate);
public var resistance:Number = 0.98;
public var elasticity:Number = 0.8;
public var floor:Number = stage.stageHeight - 100;
public var objectList:Array = new Array();
public var shadowList:Array = new Array();
public var yVelocityList:Array = new Array();
public var xVelocityList:Array = new Array();
public var massList:Array = new Array();
public var frictionList:Array = new Array();
public var lastXList:Array = new Array();
public var lastYList:Array = new Array();
public var elasticityList:Array = new Array();
public var dragList:Array = new Array();
public var spawnNum:int = 20;
public var bounding:Rectangle = new Rectangle(0,0,stage.stageWidth - 100,stage.stageHeight);
public var distantBackground:Background = new Background();
public var starLight:Light = new Light();
public function ElasticityV2() {
addChild(starLight);
starLight.x = stage.stageWidth/2;
starLight.y = -400;
starLight.addEventListener(MouseEvent.MOUSE_DOWN, onLightDrag);
starLight.addEventListener(MouseEvent.MOUSE_UP, onLightDrag);
starLight.addEventListener(MouseEvent.MOUSE_OUT, onLightDrag);
for(var s:int=0;s<spawnNum;s++){
var ballShadow:Shadow = new Shadow();
addChild(ballShadow);
setChildIndex(ballShadow,0);
ballShadow.y = floor - (ballShadow.height/2);
ballShadow.x = 100;
shadowList.push(ballShadow);
var ball:ElasticBall = new ElasticBall();
var dragging:Boolean = false;
addChild(ball);
ball.y = 100;
ball.x = s * 200;
objectList.push(ball);
yVelocityList.push(randomMe(20,-20));
xVelocityList.push(randomMe(40,-40));
massList.push(randomMe(20,5));
frictionList.push(randomMe(0.6,0.01));
objectList[s].width = objectList[s].height = massList[s] * 10;
elasticityList.push(elasticity);
dragList.push(dragging);
ball.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
ball.addEventListener(MouseEvent.MOUSE_UP, onDrag);
ball.addEventListener(MouseEvent.MOUSE_OUT, onDrag);
}
addChild(distantBackground);
distantBackground.y = stage.stageHeight - distantBackground.height;
distantBackground.width = stage.stageWidth;
setChildIndex(distantBackground,0);
addEventListener(Event.ENTER_FRAME, onGameLoop);
}
public function onGameLoop(e:Event):void{
//checkCollision();
for(var i:int=0;i<objectList.length;i++){
updatePhysics(i);
updateShadows(i,starLight);
}
}
public function updatePhysics(objRef:int):void{
if(lastXList[objRef] != undefined){
if(lastXList[objRef] != objectList[objRef].x){
xVelocityList[objRef] = objectList[objRef].x - lastXList[objRef];
}
}
if(lastYList[objRef]!= undefined){
if(lastYList[objRef] != objectList[objRef].y){
yVelocityList[objRef] = 4*(objectList[objRef].y - lastYList[objRef])/stage.frameRate;
}
}
if(objectList[objRef].y>= floor - objectList[objRef].height){
yVelocityList[objRef] = -(yVelocityList[objRef] * elasticityList[objRef]);
objectList[objRef].y = floor - objectList[objRef].height;
}
if(objectList[objRef].y<= 0){
yVelocityList[objRef] = -(yVelocityList[objRef] * elasticityList[objRef]);
objectList[objRef].y = 0;
}
if(objectList[objRef].x > (stage.stageWidth - objectList[objRef].width)){
xVelocityList[objRef]=-xVelocityList[objRef];
objectList[objRef].x = stage.stageWidth - objectList[objRef].width;
}
if (objectList[objRef].x <0){
xVelocityList[objRef]=-xVelocityList[objRef];
objectList[objRef].x = 0;
}
if(!dragList[objRef]){
yVelocityList[objRef]+=gravity;
objectList[objRef].y += yVelocityList[objRef];
xVelocityList[objRef]= (xVelocityList[objRef] * resistance);
if(-0.5<xVelocityList[objRef] && xVelocityList[objRef]<0.5){
xVelocityList[objRef] = 0;
}
objectList[objRef].x += xVelocityList[objRef];
}
lastXList[objRef] = objectList[objRef].x;
lastYList[objRef] = objectList[objRef].y;
if(xVelocityList[objRef] == 0){
xVelocityList[objRef]=randomMe(90,-90);
yVelocityList[objRef]=randomMe(90,-90);
}
}
public function onDrag(e:Event):void{
if(e.type == "mouseDown"){
setChildIndex(DisplayObjectContainer(e.target),numChildren - 1)
e.target.startDrag(false,bounding);
//xVelocityList[objRef] = yVelocityList[objRef] = 0;
//dragging = true;
}else{
e.target.stopDrag();
//dragging = false;
}
}
public function onLightDrag(e:Event):void{
if(e.type == "mouseDown"){
e.target.startDrag(false,bounding);
}else{
e.target.stopDrag();
}
}
public function updateShadows(objRef:int, lightSource:MovieClip):void{
//-----Cut for convenience------
}
public function checkCollision():void{
for(var v:int=0;v<objectList.length;v++){
var ball1 = objectList[v];
for(var w:int=v+1;w<objectList.length;w++){
var ball2 = objectList[w];
if((ball1.x + getRadius(ball1) + getRadius(ball2) > ball2.x) && (ball1.x < ball2.x + getRadius(ball1) + getRadius(ball2)) && (ball1.y + getRadius(ball1) + getRadius(ball2) > ball2.y) && (ball1.y < ball2.y + getRadius(ball1) + getRadius(ball2))){
var dx:Number = ball2.x - ball1.x;
var dy:Number = ball2.y - ball1.y;
var dist:Number = Math.sqrt((dx * dx) + (dy * dy));
if(dist < getRadius(ball1)+getRadius(ball2)){
var newX1:Number;
var newY1:Number;
var newX2:Number;
var newY2:Number;
trace("Magnitude 1 is : " + (Math.sqrt((xVelocityList[v] * xVelocityList[v]) + (yVelocityList[v] * yVelocityList[v]))));
trace("Magnitude 2 is : " + (Math.sqrt((xVelocityList[w] * xVelocityList[w]) + (yVelocityList[w] * yVelocityList[w]))));
newX1 = ((massList[v] * xVelocityList[v])+(massList[w] * xVelocityList[w]))/(massList[v] + massList[w]) * 2 - xVelocityList[v];
newY1 = ((massList[v] * yVelocityList[v])+(massList[w] * yVelocityList[w]))/(massList[v] + massList[w]) * 2 - yVelocityList[v];
newX2 = ((massList[v] * xVelocityList[v])+(massList[w] * xVelocityList[w]))/(massList[v] + massList[w]) * 2 - xVelocityList[w];
newY2 = ((massList[v] * yVelocityList[v])+(massList[w] * yVelocityList[w]))/(massList[v] + massList[w]) * 2 - yVelocityList[w];
xVelocityList[v] = newX1;
yVelocityList[v] = newY1;
xVelocityList[w] = newX2;
yVelocityList[w] = newY2;
ball1.x += newX1;
ball1.y += newY1;
ball2.x += newX2;
ball2.y += newY2;
}
}
}
}
}
public function randomMe(high:Number, low:Number = 0):Number{
return Math.random() * (high - low) + low;
}
public function getRadius(obj:MovieClip):Number{
return obj.width/2;
}
public function centerX(obj:MovieClip):Number{
return obj.x + getRadius(obj);
}
public function centerY(obj:MovieClip):Number{
return obj.y + getRadius(obj);
}
}
}
It's a very simple system to check for collision, just comparing the radius of the objects, and midair collisions seem fine, but if one ball lands on top of another that has no x or y velocity, it just sinks into it. Any ideas as to why?
I expect your balls behave like this: When one ball lands on top of the other, that's actually lying on the ground, the other ball gets pushed down into the ground, then you react at it within updatePhysics() by placing it into the position where it originated, thus, those balls become one within another. One of the suggestions that could remedy this will be to hold last collided object for each of the balls for one cycle of physics, say like this:
if(dist < getRadius(ball1)+getRadius(ball2)){
// process collision
ball1.lastCollided=ball2;
ball2.lastCollided=ball1;
}
Then, when you update your coordinates in updatePhysics(), check if lastCollided is null, if not, update that ball's coordinates and speed the same way, essentially simulating another collision. After checking for all the events within update physics cycle, assign null to lastCollided of all balls.