I am trying to make my first game in Flash, and it will be called Pedestrian Run. The rock here will come towards the player and it should be going at one consistent speed, however, every time it resets back to the starting point, it gets faster and faster. Is there any way to fix this, because I cannot for the life of me figure this out. Any help is appreciated. Here is the code on pastebin:
Pedestrian Run Code
I think the setTimeout in a recursive function is a very bad idea and it's what's probably causing your problem. Use the ENTER FRAME event for the game loop.
#Iansen is correct, your issue is caused by the setTimeout continually being called.
In your moveRock() you have a setTimeout to moveRock. Your setTimeouts are accumulating and that is why you are seeing the translation increase.
It would be best if you used a timer instead, like so:
In your class level variables:
private var moveTimer:Timer;
In your init() add this:
moveTimer = new Timer(25,0);
moveTimer.addEventListener( TimerEvent.TIMER, moveRock );
//you can call the moveTimer.start() anywhere you want, but this is fine
moveTimer.start();
Then your moveRock and spawnRock should look like this:
private function moveRock( e:TimerEvent ):void {
rock.x -= 15;
if (rock.x == char.x || rock.x == 0) {
removeChild(rock);
spawnRock();
}
}
private function spawnRock():void {
addChild(rock);
rock.x = 750;
rock.y = 520;
}
It also worth noting that the removeChild and addChild is pretty wasteful here in your current code and you'd be fine with just the moveRock() slightly altered:
private function moveRock( e:TimerEvent ):void {
rock.x -= 15;
if (rock.x == char.x || rock.x == 0) {
rock.x = 750;
rock.y = 520;
}
}
Don't use a constant value for your rock.x update. Use a variable and update it every time you "reset".
Notice in the example below, I'm updating after you despawn your previous rock.
private var speed:Number = 15;
function moveRock():void {
rock.x -= speed;
if (rock.x == char.x || rock.x == 0) {
this.removeChild(rock);
speed += 1;
spawnRock();
}
setTimeout(moveRock, 25);
}
Related
i need some help. im trying to make my character walk both direction(left and right) and an idle animation when standing still. i manage to make the character walk to the right and make the idle animation work. now if I copy the code from the right button to the left button, the walking animation gets stuck in the first frame on both direction. I tried to experiment with it but with no luck. im sorry if i sounded noob. i just started with studying programming.
here are the code that i used
RightBtn.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
function mouseDown(e:MouseEvent): void {
if(RightBtn){
isRight = true;
}
}
RightBtn.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
function mouseUp(e:MouseEvent): void {
if(RightBtn){
isRight = false;
}
}
stage.addEventListener(Event.ENTER_FRAME, loop);
function loop(Event){
if(isRight==true && mcPlayer.x < 750){
mcPlayer.x += 7;
mcPlayer.gotoAndStop (2);
mcPlayer.walkR.play ();
}
else{
mcPlayer.gotoAndStop (1)
mcPlayer.Idle.play ();
}
}
LeftBtn.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown2);
function mouseDown2(e:MouseEvent): void {
if(LeftBtn){
isLeft = true;
}
}
LeftBtn.addEventListener(MouseEvent.MOUSE_UP, mouseUp2);
function mouseUp2(e:MouseEvent): void {
if(LeftBtn){
isLeft = false;
}
}
stage.addEventListener(Event.ENTER_FRAME, loop2);
function loop2(Event){
if(isLeft==true && mcPlayer.x > 65){
mcPlayer.x -= 7;
mcPlayer.gotoAndStop (3);
mcPlayer.walkL.play ();
}
else{
mcPlayer.gotoAndStop (1)
mcPlayer.Idle.play ();
}
}
That's what you get from blatant copy&paste without learning the mechanics of how does it internally work. You set two listeners to stage, both altering mcPlayer regardless of whether it was already altered by the other one. So, you need to write both sets of code in one listener, and walk the code with your pen and paper to ensure that both isRight==true and isLeft==true branches work separately and don't interfere with each other. The proper condition statement should be like this:
if (isRight==true && mcPlayer.x < 750) {
// do a step right
} else if (isLeft==true && mcPlayer.x > 65){
// do a step left
} else {
// do idle animation
}
Your codes of initiating animation are correct themselves, they just get overridden by the listeners that are unaware of some other code altering mcPlayer.
I am making a game where insects come down from the top of the screen, and the user must kill them. The insects are in an array. Each time the user kills them, the score goes up..after a while the insects get faster and faster. When they get faster, some of them don't get killed when you click them. You have to click multiple times for them to die. I want them to get killed in one click, but this isn't working when they get faster!
function makeEnemies():void
{
var chance:Number = Math.floor(Math.random() * 150);
if (chance <= + level)
{
//Make sure a Library item linkage is set to Enemy...
tempEnemy = new Enemy();
//Math.random(); gets a random number from 0.0-1.0
tempEnemy.x = Math.round(Math.random() * 1000);
addChild(tempEnemy);
enemies.push(tempEnemy);
tempEnemy.speed = enemyBaseSpeed + ((level - 1) * speedLevelInc);
}
}
function moveEnemies():void
{
var tempEnemy:MovieClip;
for (var i:int =enemies.length-1; i>=0; i--)
{
tempEnemy=enemies[i];
if (tempEnemy.dead)
{
score++;
score++;
roachLevel.score_txt.text = String(score);
enemies.splice(i,1);
}
else // Enemy is still alive and moving across the screen
{
//rotate the enemy between 10-5 degrees
tempEnemy.rotation += (Math.round(Math.random()*.4));
//Find the rotation and move the x position that direction
tempEnemy.x -= (Math.sin((Math.PI/180)*tempEnemy.rotation))*tempEnemy.speed;
tempEnemy.y += (Math.cos((Math.PI/180)*tempEnemy.rotation))*tempEnemy.speed;
if (tempEnemy.x < 10)
{
tempEnemy.x = 11;
}
if (tempEnemy.x > stage.stageWidth - offset)
{
tempEnemy.x = stage.stageWidth - offset;
}
if (tempEnemy.y > stage.stageHeight)
{
removeEnemy(i);
lives--;
roachLevel.lives_txt.text = String(lives);
}
}
}
}
function removeEnemy(id:int)
{
removeChild(enemies[id]);
enemies.splice(id,1);
}
There is also code inside the insect.
import flash.events.MouseEvent;
import flash.display.MovieClip;
import fl.motion.Animator;
import flash.events.*;
play();
var MainTimeLine = MovieClip(root);
var mysound:squish = new squish();
this.addEventListener(MouseEvent.CLICK, kill);
this.dead = false;
function kill(e:MouseEvent):void
{
this.dead=true;
mouseChildren=false
mysound.play();
gotoAndPlay(21);
this.removeEventListener(MouseEvent.CLICK, kill);
flash.utils.setTimeout(removeSelf,2000);
}
function removeSelf():void
{
this.parent.removeChild(this);
}
You shouldn't remove an enermy from the array while iterating it.
You make enemies.splice(i,1); in your loop iterating from enemies.length to 0. While you changing your array size, you don't adjust the loop condition.
I think your main issue might be that you are reusing your insects, maybe pooling them. If you do this, you need to make sure that you are adding the eventListener for the click again when recycling.
If you are adding the listener in the constructor, that will only execute when the insect is created, not when you recycle him.
Your issue is the setTimeOut(), which is causing a memory leak. Using a timer is much safer, but if you must use it, keep a reference to the call and clear it when you no longer need it.
Also, the code you posted doesn't show where you're adding a listener to MainTimeline or parent, but if you are you need to remove that as well before the insect can be garbage collected.
Im trying to random an object(2) every time object(1).y is beyond the stage. but the problem comes that its constantly moving and sometimes its "jumps" that position where im looking to make the change.
i did try with the "if (road1.y >= stage.stageHeight) {" but it doesnt trigger.
And when I'm doing it the the speed of the movement it triggers only when it has been on the stage 2 times before.
the registration point of all MovieClips are in the TOP LEFT.
the code is this
private var road1,road4:Road1;
private var road2:Road2;
private var road3:Road3;
private var randomRoad:Sprite = new Sprite();
private var offset:Number = 0;
private var counter:Number = 0;
public function onAdded(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE,onAdded);
addChild(road1=new Road1());
addChild(randomRoad);
addChild(road4=new Road1());
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
public function onEnterFrame(e:Event):void {
if (startRandom == true) {
if (Math.random() > 0.5) {
randomRoad.addChild(road2 =new Road2());
} else {
randomRoad.addChild(road3 =new Road3());
}
startRandom = false;
trace(randomRoad);
trace(startRandom);
}
if (road1.y >= stage.stageHeight) {
startRandom = true;
trace("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz");
}
offset += speed;
counter++;
road1.y = offset % 800 - 800;
randomRoad.y = road1.y + road1.height;
road4.y = randomRoad.y + randomRoad.height;
}
Try this:
if (road1.y >= -speed) {
startRandom = true;
trace("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz");
}
What is the height of the stage? 800? Maybe the problem is in that road1.y will never go greater than -1;
Wouldn't it be more logical to base your spawning of an object on distance traveled? Then it wouldn't be reliant on determining the y position of a given road piece in relation to the screen.
I am going to assume you have a car in this game, since there is road. Give the car a distance variable and increment that variable based on the speed.
distance += speed;
if (distance > 400)
{
spawnObject();
distance = 0; // reset the distance traveled.
}
EDIT :
I think I may have misunderstood what you were trying to do as I thought you were trying to spawn objects on the side of the road and this was a method of determining when to spawn them. In re-reading it, it seems like the 'object' you are trying to spawn is the next road piece itself. Would have been better to just use the word road in your question as opposed to 'object(2)'
I'm calling a timerEvent function from enterFrame, it's running the timerEvent function on everyFrame. Is there a way to control it?
I've got my bullets firing function with timerEvent of 500, so it shoots a bullet every half a second on 24fps. It's working fine for now. Now I want to change bullet speed and skin with respect to weapon.
////////////////////////////////
//this function is called first time within an EnterFrame function
///////////////////////////////
function weaponCheck():void
{
switch (weaponState)
{
case STATE_GUN :
gun();
break;
case STATE_DOUBLE_GUN :
doubleGun();
break;
}
}
function gun():void
{
trace("single gun");
laserTimer = new Timer(600);
laserTimer.addEventListener(TimerEvent.TIMER, timerListener);
laserTimer.start();
function timerListener(e:TimerEvent):void
{
var tempLaser:MovieClip = new Laser();
var tempGunBlast:MovieClip = new Gun_blast_01();
tempLaser.x = player.x +((player.width/2)+12);
tempLaser.y = player.y;
tempGunBlast.x = stage.mouseX + 104;
tempGunBlast.y = tempLaser.y;
Lasers.push(tempLaser);
addChildAt(tempLaser,1);
addChildAt(tempGunBlast, 3);
if (tempGunBlast.currentFrame >= tempGunBlast.totalFrames)
{
removeChild(tempGunBlast);
}
}
}
function doubleGun():void
{
trace("Double gun");
doubleGunTimer = new Timer(400);
doubleGunTimer.addEventListener(TimerEvent.TIMER, timerListener2);
doubleGunTimer.start();
function timerListener2(e:TimerEvent):void
{
var tempLaser:MovieClip = new doubleG();
var tempGunBlast:MovieClip = new Gun_blast_01();
tempLaser.x = player.x +((player.width/2)+12);
tempLaser.y = player.y;
tempGunBlast.x = stage.mouseX + 104;
tempGunBlast.y = tempLaser.y;
Lasers.push(tempLaser);
addChildAt(tempLaser,1);
addChildAt(tempGunBlast, 3);
if (tempGunBlast.currentFrame >= tempGunBlast.totalFrames)
{
removeChild(tempGunBlast);
}
}
}
///////////////////////////////////////////////////
//Following function is called within an enterFrame event function
/////////////////////////////////////////////////
function playGame():void
{
weaponCheck();
blah1();
blah2();
blah3();
testForEnd();
}
function testForEnd():void
{
if (level == 3)
{
laserTimer.stop();
weaponState = STATE_DOUBLE_GUN;
weaponCheck();
}
}
So when the game runs for first time, it works fine and uses the timer event of 600 to hit the bullets, but when level == 3 and weaponState changes, the 2nd firing function doubleGun(); is called but it starts to fire the bullets on a per frame count, not on a controlled timerEvent. Please Help. Thanks.
Why don't you drop timers and use enter frame listener as a manner to count time? You are already calling weaponCheck() from an enterframe listener. Make it so that the actual gun() and doublegun() calls will only generate animation, such as firin' mah lazers and blasts, and the main function will just count time.
function weaponCheck():void
{
this.reloading+=this.weaponFiringSpeed; // you alter this to make your weapon fire slower or faster
if (this.reloading<FULLY_RELOADED) return; // we are not yet ready to fire
this.reloading=0;
switch (weaponState) // and here we fire with the gun state
{
case STATE_GUN :
gun();
break;
case STATE_DOUBLE_GUN :
doubleGun();
break;
}
}
function gun():void
{
trace("single gun");
var tempLaser:MovieClip = new Laser();
var tempGunBlast:MovieClip = new Gun_blast_01();
tempLaser.x = player.x +((player.width/2)+12);
tempLaser.y = player.y;
tempGunBlast.x = stage.mouseX + 104;
tempGunBlast.y = tempLaser.y;
Lasers.push(tempLaser);
addChildAt(tempLaser,1);
addChildAt(tempGunBlast, 3);
}
And similarly double gun. FULLY_RELOADED is a constant, reloading is a variable used to track time, it should be a property of the one who's firing.
Note, this approach requires you to manage your "tempGunBlast"s elsewhere, perhaps in the very weaponCheck function, if so, modify it as follows:
function weaponCheck():void
{
if (tempGunBlast) if (tempGunBlast.currentFrame >= tempGunBlast.totalFrames)
removeChild(tempGunBlast);
this.reloading+=this.weaponFiringSpeed; // you alter this to make your weapon fire slower or faster
if (this.reloading<FULLY_RELOADED) return; // we are not yet ready to fire
... // rest of code unchanged
You will most likely not be able to copypastely implement this, but please try.
I want to stop the movieclips movement when it hits a wall (another movieclip).
The example below works, but after the collision the movieclip 'blocks' all movement to the left...
My question to you is, is this a good way and why isn't it working well?
There will be something wrong in this code, but i'm learning.
For now the example with the leftArrow key;
variables to check the key, if it's hitting the walls and if it's moving or not:
var leftArrow:Boolean;
var speed:int = 10;
var hitting:Boolean;
var ismoving:Boolean;
event listeners for the keys/movement and detecting collision:
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
stage.addEventListener(Event.ENTER_FRAME, walking);
stage.addEventListener(Event.ENTER_FRAME, detectHit);
detecting collision function:
function detectHit(e:Event) :void
{
if(char.hitTestObject(bounds))
{
hitting = true;
}
}
function to the left arrow key:
function keyPressed(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT)
{
leftArrow = true;
}
}
function keyReleased(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT)
{
leftArrow = false;
}
}
And the reason it's not working is probably here, but I don't understand why not:
function walking(event:Event):void {
if (rightArrow) {
char.x += speed;
}
if (leftArrow && ! hitting) {
char.x -= speed;
}
else
{
ismoving = false
}
if (leftArrow && ! hitting)
char will move if hitting is false. When char.hitTestObject(bounds) is true you are setting hitting to true. You are not setting hitting again to false anywhere. That's why once left wall is hit it stops left movement permanently. You need to figure out suitable condition to set hitting to false again.
Adding an else branch in detectHit should solve the problem.
function detectHit(e:Event):void {
if(char.hitTestObject(bounds))
{
hitting = true;
} else {
hitting = false; // add this
}
}
Allthough Taskinoor's method should work, I would suggest another way to do your hittests.
Since you probably are creating a game (character and bounds), you will have more than one bound. In that case, I would strongly suggest bitmap-hittesting. This way, you can create all your bounds in one movieclip and test for a hit.
I will explain this by using the example of a maze. The maze would then be some lines in a movieclip, randomly put together. If you use HitTestObject and you aren't hitting one of the lines, but your character is over the movieclip, hitTestObject will return true, even though you are not hitting a wall. By using bitmapHitTesting, you can overcome this problem (BitmapHitTest takes transparant pixels into account, whereas hitTestObject does not).
Below you can find an example of how to do bitmapHitTesting. Creating the bitmaps in this function is not necesarry if they do not change shape. In that case, I would suggest placing the code for the bitmapdata in a added_to_stage-method.
private var _previousX:int;
private var _previousY:int;
private var _bmpd:BitmapData ;
private var _physicalBitmapData:BitmapData;
private function walkAround(e:Event):void
{
var _xTo:int = //Calculate x-to-position;
var _yTo:int = //Calculate y-to-position;
//If your character doesn't change shape, you don't have to recalculate this bitmapData over and over.
//I suggest placing it in a ADDED_TO_STAGE-Event in that case.
_bmpd = new BitmapData(char.width, char.height, true, 0);
_bmpd.draw(char);
//If your bounds are static, you don't have to recalculate this bitmapData over and over.
//I suggest placing it in a ADDED_TO_STAGE-Event in that case.
_physicalBitmapData = new BitmapData(bounds.width, bounds.height, true, 0);
_bmpd.draw(bounds);
//The below line is the actual hittest
if(_physicalBitmapData.hitTest(new Point(0, 0), 255, _bmpd, new Point(char.x, char.y), 255))
{
char.x = _previousX;
char.y = _previousY;
}
else
{
char.x = _xTo;
char.y = _yTo;
}
_previousX = char.x;
_previousY = char.y;
}
Look at my hint,
function loop(Event)
{
if(isHit==false)
{
if(isRight==true){head_mc.x+=1}
if(isLeft==true){head_mc.x-=1}
if(isUp==true){head_mc.y-=1}
if(isDown==true){head_mc.y+=1}
}
if(head_mc.hitTestObject(build_mc))
{
isHit=true;
if(isRight==true){head_mc.x-=1}
if(isLeft==true){head_mc.x+=1}
if(isUp==true){head_mc.y+=1}
if(isDown==true){head_mc.y-=1}
}
else
{
isHit=false;
}
}
I use step back to opposite direction instead.