I'm creating 2D platformer game. I'm having an issues with my collisions. When my character hits is standing on top of a platform it will stay there for 2.5 seconds then fall through all other platforms to the ground floor. I think it has to do something with my gravity function and collision function not working together properly. I really can't figure this out any help would be appreciated.
this = fireboy1
Here's gravity code from my character class:
public var gravity:int = 0;
public var floor:int = 461;
public function adjust():void
{
//applying gravity
this.y += gravity;
if(this.y + this.height <floor)
gravity++;
else
{
gravity = 0;
this.y = floor - this.height;
}
and here is the code for my collisions from the main class:
//collision detection of platform1
public function platform1Collision():void
{
if(fireboy1.hitTestObject(Platform1))
{
if(fireboy1.y > Platform1.y)
{
fireboy1.y = Platform1.y + Platform1.height;
}
else
{
fireboy1.y = Platform1.y - fireboy1.height;
}
}
Your issue is likely that the y position is being incremented every frame (regardless of any collisions)
A better approach, would be to create one game loop / Enter Frame handler, instead of having one for the player, one for each platform, etc. You also had some incorrect math with calculating players position relative to the platform and floor.
public var gravity:int = 0;
public var floor:int = 461;
//add this in your constructor or init of the class
this.addEventListener(Event.ENTER_FRAME, gameLoop);
function gameLoop(e:Event):void {
//start with all your platform collisions
if(fireboy1.hitTestObject(Platform1))
{
if(jumping){ //some flag that indicates the player is jumping at the moment
//place fireboy right under the platform
fireboy1.y = Platform1.y + Platform1.height;
}else{
//place fireboy on the platform perfectly
fireboy1.y = (Platform1.y + Platform1.height) - fireboy1.height; //changed your math here
return; //there's no use checking any other platforms or doing the gravity increment, since the player is already on a platform, so exit this method now.
}
}
//any other platform checks (should be done in a loop for sanity)
//if we made it this far (no returns), then do the gravity adjustments
fireboy1.y += gravity;
if(fireboy1.y - fireboy1.height < floor){ //changed your math here
gravity++;
} else
{
gravity = 0;
fireboy1.y = floor - fireboy1.height;
}
}
Related
I am making a brick breaker game with three frames. The first frame is the start screen, the second frame is the game itself, and the third frame is the "game over" screen (with a try again button). When I hit "Start game" the program jumps to the second frame and stops. If you fail to hit the ball with the racket, the program jumps to frame three.
My problem occurs here, because the program instantly jumps to the second frame again. Any idea why the stop(); caller fails to work? I have tried to remove all content from the last frame (except for the stop(); caller), but it still just skips back to frame 2.
I really can't figure out why this is happening. I am using Adobe Flash Professional CC. The only actionscript on frame 3 are "stop();". This is the entire code block on frame 2:
import flash.events.KeyboardEvent;
import flash.display.Stage;
import flash.events.Event;
import flash.ui.Keyboard;
import fl.transitions.Tween;
import fl.transitions.easing.*;
trace(currentFrame);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
this.addEventListener(Event.ENTER_FRAME, moveBall);
var rackert: bar = new bar();
rackert.name = "rackert";
rackert.y = 740;
rackert.x = 640;
addChild(rackert);
var ball: circle = new circle();
ball.y = 80;
ball.x = 640;
addChild(ball);
var ballXSpeed: Number = 12; //X Speed of the Ball
var ballYSpeed: Number = 12; //Y Speed of the Ball
function keyDown(e: KeyboardEvent) {
var key: uint = e.keyCode;
var step: uint = 35;
switch (key) {
case Keyboard.LEFT:
if (rackert.x > 0) {
var myTween: Tween = new Tween(rackert, "x", Regular.easeOut, rackert.x, rackert.x - step, 0.2, true);
} else rackert.x = 0;
break;
case Keyboard.RIGHT:
if (rackert.x + rackert.width < 1000) {
var myTween2: Tween = new Tween(rackert, "x", Regular.easeOut, rackert.x, rackert.x + step, 0.2, true);
} else rackert.x = 1000 - rackert.width;
break;
}
}
var gameOver: Boolean = false;
function moveBall(event: Event): void {
ball.x += ballXSpeed;
ball.y += ballYSpeed;
if (ball.x >= 1000 - (ball.width / 2)) {
ballXSpeed *= -1;
}
if (ball.x <= 0 + (ball.width / 2)) {
ballXSpeed *= -1;
}
if (ball.y >= stage.stageHeight) {
if (gameOver == false) {
gotoAndStop(3);
this.removeEventListener(Event.ENTER_FRAME, moveBall);
stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDown);
gameOver = true;
rackert.visible = false;
}
}
if (ball.y <= 22) {
ballYSpeed *= -1;
}
if (ball.hitTestObject(rackert)) {
calcBallAngle();
}
}
function calcBallAngle(): void {
var ballPosition: Number = ball.x - rackert.x;
trace("Position: " + ballPosition);
var hitPercent: Number = (ballPosition / (rackert.width - ball.width)) - .7;
trace("percent: " + hitPercent);
ballXSpeed = hitPercent * 10;
ballYSpeed *= -1;
}
function getRandom(min: Number, max: Number): Number {
return min + (Math.random() * (max - min));
}
Change this:
if (gameOver == false) {
gotoAndPlay(3); //gotoAndPlay(); caller
gameOver = true;
rackert.visible = false;
}
To:
if (gameOver == false) {
gotoAndStop(3); //gotoAndPlay(); caller
gameOver = true;
rackert.visible = false;
}
Difference is goToAndStop(). The default behavior is to "loop" an animation, so you tell it to go to frame 3 (last frame) and it "plays" through that frame back around to 1, then 2, where you most likely have a frame script that calls stop(); to stop the play head.
Update
I believe you that you're calling stop(); in frame 3. It seems like it should work and indeed it actually is, it's just not working on the object that you're expecting it to work on. Since you're using a frame script, stop(); is being called on the InteractiveObject who's scope the frame script is inside of. Let me clarify.
Frame 3 Of Stage
-> Child on frame three called FrameScriptsArePITA
-> Double click FrameScriptsArePITA and write a frame script "stop()", the script will do nothing but stop FrameScriptsArePITA from playing.
Watch your scope. That's part of why frame scripts are... best to avoid. Using your own DocumentClass and hooking everything in your design view into corresponding classes will make things easier to solve in AS3.
I finally found the issue. I had a timer event on frame 1, which caused the bug. I simply used removeEventListener for the timer function where i skip to frame 2. As Technick Empire said, you should always be cleaning up anything including even listeners as they can even interfere with the garbage collector and cause memory leaks.
I'm trying to make a basic game in Flash and Actionscript 3.
As of now, I've been working on a smooth game loop but ran into problems. I tried to implement a fixed time-stamp loop seen: http://gafferongames.com/game-physics/fix-your-timestep/ and in Flixel.
The main issue that I have right now is that moving a simple object across the screen produces noticeable stuttering. I am aiming for a smoother experience but can't seem to figure out what the issue is.
The main loop is called on an Event.ENTER_FRAME at 60 fps.
These variables are instantiated first:
public var total:uint = 0;
public var fixedDT:Number = 1000.0/60.0; //Shoot for 60 FPS in MS
public var accumulator:int = 0;
public var maxAccumulation:uint = 120;
This is the main loop on every ENTER_FRAME:
//Most times are in ms
var mark:uint = getTimer();
var elapsedMS:uint = mark-total;
total = mark;
accumulator += elapsedMS;
if(accumulator > maxAccumulation){
accumulator = maxAccumulation;
}
while(accumulator > fixedDT){
step();
accumulator = accumulator - fixedDT;
}
//Convert from ms to secs. to interpolate graphics drawing (linear interpolation)
renderGameState(accumulator/fixedDT/1000.0);
step() is just updating every game-object with the fixed delta-time. The game object update function is simple and is as follows:
//First part is just updating the previous position for graphic interpolation
position.x += velocity.x*deltaTime;
position.y += velocity.y*deltaTime;
For rendering, I am just drawing bitmap.copyPixel. The graphical interpolation I mentioned is using a basic linear interpolation function that uses prev./curr. position and deltaTime to calculate the drawX/Y.
public function render(bitmap:BitmapData, deltaTime:Number, xOff:Number, yOff:Number):void{
this.x = lerp(prevPosition.x,position.x,deltaTime) + xOff;
this.y = lerp(prevPosition.y,position.y,deltaTime) + yOff;
bitmap.copyPixels(bitmapData, bitmapData.rect,new Point(this.x,this.y),null,null,true);
}
public function lerp(v0:Number, v1:Number, t:Number):Number {
return (1-t)*v0 + t*v1;
}
However, there is noticeable stuttering appearing. In the image below, I don't clear the bitmap before drawing to it. You should be able to see that there's a lot of variation between the spacing of circles rendered, and sometimes it's extremely noticeable.
http://i.stack.imgur.com/00c39.png
I would appreciate any help at all, thanks!
I don't know if this helps but here's the code I use to fix my time step.
private var _pause :Boolean;
private var _prevTimeMS :int;
private var _simulationTime :Number;
override public function update():void
{
super.update();
if (!_pause)
{
var curTimeMS:uint = getTimer();
if (curTimeMS == _prevTimeMS)
{
return;
}
var deltaTime:Number = (curTimeMS - _prevTimeMS) / 1000;
if (deltaTime > 0.05)
{
deltaTime = 0.05;
}
_prevTimeMS = curTimeMS;
_simulationTime += deltaTime;
while (space.elapsedTime < _simulationTime)
{
// Your game step goes here.
_space.step((stage.frameRate > 0) ? (1 / stage.frameRate) : (1 / 60));
}
}
}
(Originally taken from a Nape Physics sample)
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.
This is the code i have got so far for a single falling object. The 'DangerIN' is the instance name for the object that is falling down. The class is named 'Danger'. So how can i make it loop so it falls continuously and when it reaches certain y value it will remove it self. Also i want more than one(abount 5) objects falling down at once.
var randomX:Number = Math.random() * 550;
DangerIN.x = randomX;
DangerIN.y = 96;
var speed:Number = Math.random()*10;
DangerIN.addEventListener(Event.ENTER_FRAME, moveDown);
function moveDown(e:Event):void {
e.target.y += speed;
if(e.target.y >= 610) {
DangerIN.removeEventListener(Event.ENTER_FRAME, moveDown);
}
}
It's easy. But to do that, you first need an Array of falling stuff, and then you need to reposition your e.target to the top once it's below your threshold.
function moveDown(e:Event):void {
e.target.y += speed;
if (e.target.y >= 610) {
// reposition
e.target.x=math.random()*550;
e.target.y=96;
}
}
Assign this function to every object you want to fall down, reach bottom and reappear back up.
To remove itself you can add a following line after the removeEventListener():
parent.removeChild(this);
But it's not pretty and you probably should to it the right way:
Store all the Danger objects in the array, in the Danger class create a function like go(), moveDown() or something:
public function go():void
{
y+= speed;
}
and in the class where you create the Danger objects make a loop like this:
private function loop():void
{
for (var i:int = dangerObjArray.lenght - 1; i >= 0; i--)
{
dangerObjArray[i].go();
if (dangerObjArray[i].y >= maxY)
dangerObjArray.splice(i , 1);
}
}
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)'