AS 3 Error Null Object - actionscript-3

I've got an error in my game in AS3. When my array lenght is 0 the app should go to the Menu scene. However it always appears a box saying:
TypeError: Error #2007: Parameter child must be non-null.
at flash.display::DisplayObjectContainer/removeChild()
at kitkat_game_fla::MainTimeline/moveBall()[kitkat_game_fla.MainTimeline::frame2:105]
I click on dismiss all and when i start the game again the ball is completely fast. What should i do. Is it because my mcBall.x is null and it shouldn´t? I already search and nothing works. Some help please.
Here's my code
stop();
var ballSpeedX:int = 23;//Velocidade em X da bola.
var ballSpeedY:int = 23;//Velocidade em Y da bola.
var mySound:Sound = new myFavSong();
var myArray:Array = new Array(mc1,mc2);
trace (myArray.length);
function iniciarCode():void{
mcPaddle.addEventListener(Event.ENTER_FRAME, movePaddle);
mcBall.addEventListener(Event.ENTER_FRAME, moveBall);
}
function movePaddle(event:Event):void{
var dx:int = mcPaddle.x - mouseX;
mcPaddle.x -= dx / 5;
if(mcPaddle.x <= mcPaddle.width/2){
mcPaddle.x = mcPaddle.width/2;
}else if(mcPaddle.x >= stage.stageWidth-mcPaddle.width/2){
mcPaddle.x = stage.stageWidth-mcPaddle.width/2;
}
}
function moveBall(event:Event):void{
mcBall.x += ballSpeedX;
mcBall.y += ballSpeedY;
if(mcBall.x <= mcBall.width/2){
mcBall.x = mcBall.width/2;
ballSpeedX *= -1;
} else if(mcBall.x >= stage.stageWidth-mcBall.width/2){
mcBall.x = stage.stageWidth-mcBall.width/2;
ballSpeedX *= -1;
}
if(mcBall.y <= mcBall.height/2){
mcBall.y = mcBall.height/2;
ballSpeedY *= -1;
} else if(mcBall.y >= stage.stageHeight-mcBall.height/2){
mcBall.y = stage.stageHeight-mcBall.height/2;
ballSpeedY *= -1;
}
if(mcBall.hitTestObject(mcPaddle)){
calcBallAngle();
}
if(mcBall.hitTestObject(mc_lettering)){
calcBallAngle();
}
if(mcBall.hitTestObject(mc1)){
removeChild(mc1);
myArray.splice(mc1, 1)
trace(myArray.length);
mc1 == null;
}
if(mcBall.hitTestObject(mc2)){
removeChild(mc2);
myArray.splice(mc2, 1);
trace(myArray.length);
mc2 == null;
}
if(myArray.length == 0){
gotoAndPlay(1,"Menu");
}
if(mcBall.hitTestObject(mcPaddle.barra_mc1)){
mcPaddle.removeChild(mcPaddle.barra_mc1);
mcPaddle.barra_mc1 == null;
mySound.play();
}
}
function calcBallAngle():void{
var ballPosition:Number = mcBall.x - mcPaddle.x;
var hitPercent:Number = (ballPosition / (mcPaddle.width - mcBall.width)) - .5;
ballSpeedX = hitPercent * 30;
ballSpeedY *= -1;
}
iniciarCode();

myArray.splice(mc2, 1); is a wrong approach, because the first parameter to splice() is an index, not an object. You should instead query indexOf() for that object, and if it's off the array already, you don't splice and don't call removeChild().
if (mc1) if (mc1.parent) // if mc1 is detached, why checking hit test?
if(mcBall.hitTestObject(mc1)){
removeChild(mc1);
myArray.splice(myArray.indexOf(mc1), 1) // at this point mc1 is still in array
trace(myArray.length);
// mc1 == null; this is wrong, unless you create a new mc1 at the start of the game
// and it should spell one equal sign, not two.
}
if (mc2) if (mc2.parent)
if(mcBall.hitTestObject(mc2)){
removeChild(mc2);
myArray.splice(myArray.indexOf(mc2), 1);
trace(myArray.length);
// mc2 == null;
}
Also such an approach defies the use of an array. Normally you don't query the individual MCs, but instead you iterate through the array and run hitTestObject against every item in the array. Like this:
for (var i:int=myArray.length-1;i>=0;i--) {
if (mcBall.hitTestObject(myArray[i])) {
removeChild(myArray[i]);
myArray.splice(i,1);
// that's all
}
}
if (myArray.length==0) { gotoAndPlay(1,"Menu"); }
Also, please get rid of "scenes", they are deprecated and can cause weird issues. Instead, use one scene and split it into frame sequences via timeline stop() calls.

Related

How do i detect collision and stack falling objects in as3 flash?

I have a little problem when I'm trying to get the sqares to stack, almost like in tetris.
I don't know how I can controll the different squares so i can check for collision. I have made one square with as3 linkage name Square.
var timer:Timer = new Timer(12);
timer.addEventListener(TimerEvent.TIMER, doStuff);
timer.start();
var newSquare= new Square();
nyFirkant.y = 0;
nyFirkant.x = Math.floor( Math.random() * 4) * 100;
addChild(newSquare);
stage.addEventListener(KeyboardEvent.KEY_DOWN, tastLytter);
function keyListener(evt:KeyboardEvent)
{
var key:int = evt.keyCode;
if (key== Keyboard.RIGHT && newSquare.x < 400)
{
newSquare.x += 100;
}
if (key== Keyboard.LEFT && newSquare.x > 0)
{
newSquare.x -= 100;
}
}
function doStuff(evt:TimerEvent)
{
if (newSquare.y <= 400 - newSquare.height)
{
newSquare.y = newSquare.y + 2;
}
if (newSquare.y == 350)
{
newSquare= new Square();
newSquare.y = 0;
newSquare.x = Math.floor( Math.random() * 4) * 100;;
addChild(newSquare);
}
}
Use hitTestObject, it's a method in the MovieClip class.
if (firstBlock.hitTestObject(secondBlock)) {
trace("This block hit the other block");
//Do stuff
}
Obviously this isn't a "drop-in" solution - you'd be much better off using a physics engine such as Box2D, but hitTestObject should do fine for your purposes.

How can I code an object to spawn onto the stage in the Actions panel?

I am trying to introduce a new ball into my pong game, sort of like a power up. I am writing all of my code in the Actions panel in the first frame. The new ball should appear on the stage and start moving around randomly like the original ball. Although I am using a code snippet and not .as file. So all of my code is in the Actions panel(Accessed by pressing f9).
I would also like my dynamic text box to merge with the stage colour so that you can't see the white background.
I can't show you what the fla looks like because I have less than 10 reputation, but the dynamic text box will not merge into the background and instead has a white surrounding. This hides the ball when the ball goes up.
import flash.events.Event;
import flash.ui.Mouse;
//hide mouse
Mouse.hide();
init(); //initialises everything
var bSpeedX:int = -3.5;
var bSpeedY:int = -2.5;
// assign a maximum speed to the AI
var compPaddleSpeed:int = 3.5;
var pScore:int = 0;
var cScore:int = 0;
// Updates the score
function scoreUpdate():void {
playerScore.text = ("Player Score: " + pScore);
computerScore.text = ("AI Score: " + cScore);
}
function init():void //tells flash not to return values
{
stage.addEventListener(Event.ENTER_FRAME, loop);
}
/*we want the ySpeed to be larger if there
is a greater difference between the y
positions of the ball and paddle, so I started with
(gameBallY-padY). To convert this difference
into a number between -1 and 1, I divided
this number by 25, which
is half the height of the paddle. Finally, I wanted
the ySpeed to be more powerful than
just -1 to 1, and after a bit of trial and error
I decided to times by 5 at the end
to change the total magnitude of the new ySpeed.*/
//defying the laws of Physics
function calculategameBallAngle(padY:Number, gameBallY:Number):Number
{
var ySpeed:Number = 5 * ((gameBallY-padY) / 25 );
return ySpeed;
}
//main loop
function loop(e:Event):void
{
//makes the paddle track the mouse
playerPaddle.y = mouseY;
//paddle AI
if(compPaddle.y < gameBall.y - 10){
compPaddle.y += compPaddleSpeed;//make it go up
} else if(compPaddle.y > gameBall.y + 10){
compPaddle.y -= compPaddleSpeed;//make it go down
}
//Collisions
if( playerPaddle.hitTestObject(gameBall) == true ){
if(bSpeedX < 0){
bSpeedX *= -1;
bSpeedY = calculategameBallAngle(playerPaddle.y, gameBall.y);
}
} else if(compPaddle.hitTestObject(gameBall) == true ){
if(bSpeedX > 0){
bSpeedX *= -1;
bSpeedY = calculategameBallAngle(compPaddle.y, gameBall.y);
}
}
//makes the gameBall move
gameBall.x += bSpeedX; //each frame, we add the bSpeedX to the ball's x position.
gameBall.y += bSpeedY; //same for the bSpeedY to the ball's y postion.
// checks to see if the ball misses the paddle
if(gameBall.x <= gameBall.width/2){
gameBall.x = gameBall.width/2;
bSpeedX *= -1;
cScore ++;
scoreUpdate();
//keeps the ball within the stage
} else if(gameBall.x >= stage.stageWidth-gameBall.width/2){
gameBall.x = stage.stageWidth-gameBall.width/2;
bSpeedX *= -1;
pScore ++;
scoreUpdate();
}
if(gameBall.y <= gameBall.height/2){
gameBall.y = gameBall.height/2;
bSpeedY *= -1;
}
else if(gameBall.y >= stage.stageHeight-gameBall.height/2){
gameBall.y = stage.stageHeight-gameBall.height/2;
bSpeedY *= -1;
}
//-------------------------------------------------------
//keeps the player paddle within the stage
//check if paddle is above top of the screen
if(playerPaddle.y - playerPaddle.height/2 < 0){
playerPaddle.y = playerPaddle.height/2;
} else if(playerPaddle.y + playerPaddle.hieght/2 > stage.stageHeight){
playerPaddle.y = stage.stageHeight - playerPaddle.height/2;
//check if paddle is below bottom of the screen
} else if(playerPaddle.y + playerPaddle.height/2 > stage.stageHeight){
playerPaddle.y = stage.stageHeight - playerPaddle.height/2;
}
}
If you only want your ball to be replaced with new one which has diffrent grphics and/or speed you can for example export your ball class to action script:
Library>RMB on your symbol>Properties>ActionScript Linkage>Export for ActionScript
Type your class name under Class: field like "MyBallClass" and hit OK.
Now you can construct this ball in your code and replace old one like this:
var newBall:MyBallClass = new MyBallClass();
addChild(newBall);
newBall.x = gameBall.x; newBall.y = gameBall.y;
gameBall = newBall;
Additionally you can define new variable like var speedModifier:Number = 1; to use with:
gameBall.x += bSpeedX * speedModifier;
gameBall.y += bSpeedY * speedModifier;
And change that also when you change the ball.
If You want to have multiple balls at same time You really should consider build this in OOP. For simplest example in addition to previous one
You can create MyBallClass.as file and write in it something like:
package
{
import flash.display.Sprite;
import flash.geom.Point;
public class MyBallClass extends Sprite
{
public var speedFactor:Number;
public var speed:Point = new Point(-3.5, -2.5);
public function MyBallClass(x:Number, y:Number, speedFactor:Number = 1)
{
this.x = x; this.y = y;
this.speed = speed;
}
}
}
Now you can create container for all the balls in yor game.
var balls:Vector<MyBallClass> = Vector<MyBallClass>([]);
and run your physics for all of them in a loop.
Generally main code would look something like this:
var balls:Vector.<MyBallClass> = Vector.<MyBallClass>([]);
addBall(...)//place first ball.
function loop(e:Event):void {
processBalls();
if(wantToAddNewSuperSpeedBall) addBall(x,y,3);
...
}
function processBalls() {
for (var i:int = 0; i < balls.length; i++) {
detecCollision(balls[i]);
moveBall(balls[i]);
//any code that process a single ball...
}
}
function addBall(x:Number, y:Number, speedFactor:Number = 1) {
var newBall:MyBallClass = new MyBallClass(x,y, speedFactor);
addChild(newBall);
balls.push(newBall);
}
function moveBall(ball:MyBallClass) {
ball.x += ball.speed.x * ball.speedFactor;
ball.y += ball.speed.y * ball.speedFactor;
}
So you should modify all functions which affect ball behavior to work with ball passed as argument, not only one specific instance and then use them for all balls.
There are more to cover in this topic and this isn't maybe the best approach but I've tried to make it easy to understend. There a lot of guides for OOP so you can get better idea about what is going on if you read them.
I hope that helped you somehow.

Compile-time constant error Actionscript 3

I am currently trying to put together a platformer game similar to doodlejump however I am getting two errors that I am unsure of how to fix. Below is the code that I am currently using. My errors are;
**Scene 1, Layer 'Code', Frame 4, Line 181 1046: Type was not found or was not a compile-time constant: stick.
Scene 1, Layer 'Code', Frame 4, Line 207 1180: Call to a possibly undefined method stick.**
var tempStick:stick;
var tmpMc:MovieClip;
stop();
// MONITOR THE ACCELEROMETER
var myAcc:Accelerometer = new Accelerometer();
myAcc.addEventListener(AccelerometerEvent.UPDATE, onAccUpdate);
function onAccUpdate(evt:AccelerometerEvent):void{
accX = evt.accelerationX;
}
//MONITOR THE ENTER_FRAME EVENT
stage.addEventListener(Event.ENTER_FRAME, onMyEnterFrame);
//INIT STAGE WITH CLOUDS
if (firstPass == 1){
liveScore = 0;
accX = 0;
for (var i:int=0; i< 5; i++){
tempStick = new stick;
tempStick.x = Math.random()*stage.stageWidth;
tempStick.y = 0 + i*stage.stageHeight/6;
myVect[i] = tempStick;
addChild(tempStick);
tempStick.cacheAsBitmap = true;
}
firstPass = 2;
}
function onMyEnterFrame(evt:Event):void{
//MOVE X DEPENDING ON THE ACCELEROMETER
MyIcare.x -= (MyIcare.x - (MyIcare.x + accX * 10))*0.6;
//MOVE HEAD TO THE LEFT OR TO THE RIGHT
if(accX > 0) {
MyIcare.gotoAndStop(2);
}else{
MyIcare.gotoAndStop(1);
}
// Vertical speed OF THE ICARE/ANGEL
vVelocity += vAcceleration;
if((MyIcare.y > middleScreen) && (vVelocity < 0)){
// ICARE IS GOING UP
MyIcare.y += vVelocity;
}else{
if(vVelocity > 0){
// ICARE IS GOING DOWN
MyIcare.y += vVelocity;
// TEST IF ICARE TOUCHES A CLOUD
for (var i:int=0; i< 5; i++){
tmpMc = myVect[i];
if (MyIcare.hitTestObject(tmpMc))
{
vVelocity = -20;
}
}
}else{
// THE WORLD IS GOING DOWN
// WHEN ICARE IS IN THE MIDDLE OF THE SCREEN
for (var j:int=0; j< 5; j++){
tmpMc = myVect[j];
tmpMc.y -= vVelocity;
}
liveScore += 5;
}
}
// CHECK IF THE CLOUDS ARE OUT OF THE SCREEN
if(myVect[0] != null){
for (var k:int=0; k< 5; k++){
tmpMc = myVect[k];
if(tmpMc.y > stage.stageHeight){
tmpMc.y = -5;
tmpMc.x = Math.random()*stage.stageWidth;
}
}
}
//ICARE IS OUT OF THE SCREEN
//PAUSE GAME
MyIcare.y = -300;
vVelocity = 0;
vAcceleration = 0;
// PLAY FUNNY SOUND
}
Most likely your problem is you haven't told your library object (stick) to be accessible to code.
To do that, open your library panel in FlashPro, right click your stick asset/movieClip, and choose properties.
On the Symbol Properties Window, check the Export For ActionScript box. Then enter stick as in the Class field.
Now you can instantiate a stick through code.

Flash As3 Variable Issue

I have a variable on frame 1 that starts at 3000 and keeps decreasing. This variable determines the gap of time between the spawn of an object. so basically the objects spawn quicker and quicker as the this number decreases. Everything works fine except the fact when i make the character die and the main timeline goes to frame 2 to show the death screen. When clicked "play again" on that frame that makes you come back to frame 1. the objects keep spawning at whatever speed they were spawning before death. Even though the variable resets to 3000 when "play again" clicked..
I traced the variable and it does truely reset. but for some reason those spawning objects follow the previous variable.
Heres the code on the first Frame:
import flash.events.Event;
stop();
var num1:Number = 0;
var scrollSpeed:Number = 3000;
var playerState:Number = 1;
var alive:Boolean = true;
var Redbars:Array = new Array();
var Bluebars:Array = new Array();
var scoreCount:Number = 10;
addEventListener(Event.ENTER_FRAME, update);
function update(e:Event){
trace(scrollSpeed);
scoreCount += 1;
scoreText.text = (scoreCount).toString();
//SCROLL SPEED-------------------
if(scrollSpeed > 300)
{
scrollSpeed -= 1;
}
//--------------------------------
CheckForCollisionBlue();
CheckForCollisionRed();
//trace(alive);
if(player.currentFrame == 1){
playerState = 1;
}
//Check if lost
if(player.hitTestObject(leftHitBox)){
gotoAndStop(2);
scoreEnd.text = (scoreCount).toString();
}
//If dead Delete Object
if(currentFrame == 2){
deleteBlue();
deleteRed();
}
}
////
//Timer////////////////////////////////
var myTimer:Timer = new Timer(scrollSpeed,10000000);
myTimer.addEventListener(TimerEvent.TIMER, timerListener);
function timerListener (e:TimerEvent):void{
//Generate Random number
num1 = randomRange();
trace(num1);
//IF NUM1 = 1------------------------------------------
if(num1 == 1){
//Create a Red Bar
var redBar = new Jump_Cube();
Redbars.push(redBar); //add enemy to the array
redBar.x = -33;
redBar.y = 99;
redBar.width = 12.5;
redBar.height = 20.45;
//Update the Bar
for(var i:int=0; i < Redbars.length; i++){
if(currentFrame == 1)
{
addChild(Redbars[i]);
}
}
}
//IF NUM1 = 2------------------------------------------
if(num1 == 2){
//Create a Blue Bar
var blueBar = new Jump_Cube2();
Bluebars.push(blueBar); //add enemy to the array
blueBar.x = -26.8;
blueBar.y = 10;
blueBar.width = 12.25;
blueBar.height = 31.90;
//Update the Bar
for(var j:int=0; j < Bluebars.length; j++){
if(currentFrame == 1)
{
addChild(Bluebars[j]);
}
}
myTimer.delay = scrollSpeed;
}
}
myTimer.start();
//--------------------------------------------------------------------
//Check for Collision------------------------------
function CheckForCollisionBlue(){
for(var i:int=0; i < Bluebars.length; i++){
if( player.hitTestObject(Bluebars[i]) ){
//Collision
trace("Didnt Hit Blue");
player.x -= 5;
player.y += 1;
}
}
}
//Check for Collision------------------------------
function CheckForCollisionRed(){
for(var i:int=0; i < Redbars.length; i++){
if( player.hitTestObject(Redbars[i]) ){
//Collision
trace("Didnt Hit Red");
player.x -= 5;
player.y += 1;
}
}
}
function randomRange():Number
{
return (Math.floor(Math.random() * (2 - 1 + 1)) + 1);
}
///////////BUTTONS------------------
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
redButton.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchEndRed);
function onTouchEndRed(e:TouchEvent):void{
player.gotoAndPlay(2);
playerState = 2;
}
blueButton.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchEndBlue);
function onTouchEndBlue(e:TouchEvent):void{
player.gotoAndPlay(19);
playerState = 3;
}
///////--CLEARING STAGE
//--------------------------------------------------------------------
//delete Blue------------------------------
function deleteBlue(){
for(var i:int=0; i < Bluebars.length; i++){
removeChild(Bluebars[i]);
}
}
//delete Red------------------------------
function deleteRed(){
for(var i:int=0; i < Redbars.length; i++){
removeChild(Redbars[i]);
}
}
Heres the code on the second frame:
stop();
alive = false;
againButton.addEventListener(TouchEvent.TOUCH_END, again);
function again(e:TouchEvent):void{
gotoAndStop(1);
playerState = 1;
scrollSpeed = 3000;
deleteBlue();
deleteRed();
}
You have to put in a removeEventListener(Event.ENTER_FRAME, update); inside your onTouchEndRed function. And probably also inside of this 'if' conditional: if(player.hitTestObject(leftHitBox)){...
Simply stop programming using frames. Use classes instead. AS3 is based on classes. It'll take you a lot of benefits. This link may help you to start: http://www.adobe.com/devnet/actionscript/getting_started.html
Additionally, FlashPlayer executes frame's code each time you jump to another frame. Thats why your variables are reinitializing.

ActionScript 3 - Walls don't collide properly

For several weeks I'm been trying to make my topdown game. It went well for some time, but then at some point I wanted to create a scrolling map with walls everywhere. Now, to make it easy to create the map (and add more later) I made a class called "Wall" which I will hit test. This works, when it hits, the map must stop scrolling. It does, so good so far.
Now, when the player moves away from the object, I want the map to be able to scroll again, this works too, but now the player can't move to the side the player came from. I know this is because I need to define the sides, where the player enters, in order tell the game which movement must be set to zero at that point.
You can see the code here:
public function AddWalls(player:MovieClip)
{
WallObjects = new Array();
for (var i:int = 0; i < this.numChildren; i++)
{
var mc = this.getChildAt(i);
if (mc is Wall)
{
var wallobj:Object = new Object();
wallobj.mc = mc;
wallobj.leftside = mc.x;
wallobj.rightside = mc.x + mc.width;
wallobj.topside = mc.y;
wallobj.bottomside = mc.y + mc.height;
wallobj.width = mc.width;
wallobj.height = mc.height;
WallObjects.push(wallobj);
}
}
}
public function EnableCollisionWithWalls():void
{
for (var k:int = 0; k < WallObjects.length; k++)
{
//if (player.y > WallObjects[k].topside && player.y < WallObjects[k].bottomside && player.x > WallObjects[k].leftside && player.x < WallObjects[k].rightside)
if (player.hitTestObject(WallObjects[k].mc))
{
if (player.x > WallObjects[k].leftside && player.x < WallObjects[k].leftside+15)
{
Lefthit = true;
trace(DebugVar);
DebugVar++;
player.x = WallObjects[k].leftside;
Scroll_x = 0;
}
else
if ( player.x < WallObjects[k].leftside -1 || (player.y > WallObjects[k].leftside ))
{
Lefthit = false;
}
if (player.hitTestObject(derp))
{
Lefthit = false;
}
}
}
}
public function EnableMovement():void
{
map.x += Scroll_x;
map.y += Scroll_y;
for (var i:int = 0; i < this.numChildren; i++)
{
var mc = this.getChildAt(i);
if (mc is Wall)
{
mc.x += Scroll_x;
mc.y += Scroll_y;
}
}
}
public function MovementKeysDown(move:KeyboardEvent):void
{
var Speed:int = -5;
switch (move.keyCode)
{
case 37: // venstre knap
Scroll_x = -Speed;
break;
case 38: // op
Scroll_y = -Speed;
break;
case 39: // højre knap
Scroll_x = Speed;
if (Lefthit)
{
Scroll_x = 0;
}
break;
case 40: // ned
Scroll_y = Speed;
break;
default:
}
}
public function MovementKeysUp(move:KeyboardEvent):void
{
switch (move.keyCode)
{
case 37:
Scroll_x = 0;
break;
case 38:
Scroll_y = 0;
break;
case 39:
Scroll_x = 0;
break;
case 40:
Scroll_y = 0;
break;
default:
}
}
Might be some syntax errors (since I removed some code in this editor).
You can see the current version here.
In this version the scroll keeps on going. I did come up with a "fix" for it, by check if the player was 1 pixel away from the movieclip, inside the hit test (which for some reason works, which I guess it shouldn't since it doesn't hit anymore) and then setting the Lefthit to false. However this is not a good solution and if you continue up or down away from the movieclip, you are still not able to go right anymore...
I've been baffled by this for a long time, so I thought it was about time I asked for help. I couldn't find anything on how to control movement in a top-down game, with a scrolling map + wall :/
The simplest (but not most resource friendly) solution (if you anyway have a single storage for walls) is iterating through the walls and instead of using the Flash default hitTest (I don't like the way it works since ActionScript 2) - just check the coordinates and if you see that there's going to be a collision on the next simulation step - handle it according to the game logic.
The most useful optimization for this algorithm is creating a filter/data structure for getting only walls that are near to the player and so can be affected to the test for collisions.