MovieClip Y position becomes negative on update loop using delta time - actionscript-3

I am coding a game in flash AS3 and I have implemented my game loop using the answer provided here: Is this a good implementation of the gameloop
However, after increasing my movieclip's y position by dist (dist is from speed * timeElapsed) the movieclip's y position becomes negative.
I have noticed this negative value by tracing the movieclips position on each update.
See code:
public class GameWorld extends MovieClip {
var speed:Number = 250;
var balls:Array = [];
private var _lastTime:Number = 0;
public function GameWorld() {
createballs();
this.addEventListener(Event.ENTER_FRAME, loop);
}
public function loop(e:Event):void
{
var now = new Date().getTime();
var _delta = now - _lastTime;
_lastTime = now;
updateGameState(_delta/1000);
}
public function updateGameState(timeElapsed:Number):void
{
var dist:Number = speed * timeElapsed;
balls[0].y += dist;
trace(balls[0].y);
}
public function createballs():void
{
for(var i:int = 0; i < 1; i++)
{
var ball:Ball = new Ball();
ball.y = 100;
ball.x = 100;
addChild(ball);
balls.push(ball);
}
}
}
I would like to know what is causing this sudden negative value of movieclips y position.

Yeah as #Vesper suggested, I have found the issue to be the first delta value which is very large as _lastTime is zero. The solution is to get the current time before the loop begins (before adding event listener on stage) and use that as the lastTime in the first update i.e.
....
_lastTime = new Date().getTime();
//this is the looper function called on each frame
this.addEventListener(Event.ENTER_FRAME, _onEnterFrame);
}
public function _onEnterFrame(e:Event):void
{
var now = new Date().getTime();
var _delta;
_delta = now - _lastTime;
_lastTime = now;
updateGameState(_delta/1000);
}
This way the first _deltaTime is so small close to zero hence dist will be zero which is exactly true as the objects starting point is 0 relative to itself.

Related

Trying to get AS3 to detect collision but get Error 1009 (Null Object)

I've just only began learning AS3 as I have to create a simple game for an assignment, I have two objects named obj_laser and obj_enemy1 but when I run the collision code I created, it keeps coming up with the error 1009. Here is some of the code and I know its messy.
stage.addEventListener(Event.ENTER_FRAME, runGame);
function runGame(event: Event): void {
//Fire Laser
LASERALARM++;
if (LASERALARM >= 10) {
var laser: obj_laser = new obj_laser
var laser2: obj_laser = new obj_laser
var flare: obj_flare = new obj_flare
var flare2: obj_flare = new obj_flare
laser.x = obj_spaceship.x + 12
laser.y = obj_spaceship.y
laser2.x = obj_spaceship.x - 12
laser2.y = obj_spaceship.y
addChild(laser);
addChild(laser2);
flare.x = obj_spaceship.x + 12
flare.y = obj_spaceship.y
flare2.x = obj_spaceship.x - 12
flare2.y = obj_spaceship.y
addChild(flare);
addChild(flare2);
LASERALARM = 0;
//Move Laser
laser.addEventListener(Event.ENTER_FRAME, moveLaser);
function moveLaser(event: Event): void {
laser.y -= 5;
laser2.y -= 5;
}
}
//Spawn Enemies
ENEMYALARM++
if (ENEMYALARM >= (randomRange(100, 400))) {
var enemy1: obj_enemy1 = new obj_enemy1
enemy1.x = (randomRange(15, 165));
enemy1.y = -10;
addChild(enemy1);
ENEMYALARM = 0;
//Move Enemy
enemy1.addEventListener(Event.ENTER_FRAME, moveEnemy);
function moveEnemy(event: Event): void {
enemy1.y += 2;
}
if (laser.hitTestObject(enemy1)) {
parent.removeChild(laser);
parent.removeChild(enemy1);
}
}
Essentially you are trying to do something with a variable that doesn't have a value.
Clicking on the error should take you to where it breaks down in the code. Further to that, start tracing out your variables at different points of the code to try and nail it down.

event.localX of a MovieClip regardless of any other DisplayObject over/under/inside

Here is an example:
var table:Table = new Table();
stage.addChild(table);
//table covers the whole stage
for (var i:int = 0; i<= 10; i++){
var book:Book = new Book();
book.x = Math.random() * stage.stageWidth;
book.y = Math.random() * stage.stageHeight;
if (Math.random() < .5){
stage.addChild(book)
}
else {
table.addChild(book)
}
stage.addEventListener(MouseEvent.CLICK, clicked);
function clicked(event:MouseEvent){
trace(event.localX, event.localY);
}
what i need here is the localX or localY OF THE TABLE, not anything else.
so the general question is "how to return event.localX of a certain MovieClip regardless of any other DisplayObject over/under/inside it, without setting the mouseChildren to false (as I need them to be enabled)"
You can use DisplayObject's globalToLocal method to convert a Point from being relative to the stage to being relative to the table object.
function clicked(event:MouseEvent){
var globalPt:Point = new Point(event.stageX, event.stageY);
var tablePt:Point = table.globalToLocal(globalPt);
trace(tablePt.x, tablePt.y);
}

Some of the collisions are not responding

im developing a game; its like a space craft going horizontally and enemy crafts coming oppositely..Enemies are destroyed only when it collides with the trail of the craft.
Here is the main class:
public function Velocity() {
//int static var
trailspeed = 10;
shipspeed = 5;
//init ship//
ship = new Ship();
ship.x = 337;
ship.y = 216;
//int arrays
enemies = new Array();
//init starting state
score = 0;
health = 100;
//Events
addEventListener(Event.ENTER_FRAME, motion);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keydown);
stage.addEventListener(KeyboardEvent.KEY_UP, keyup);
//init container and trail
_cont = new MovieClip();
//addChild
addChild(_cont);
addChild(ship);
timerset();
}
public function motion(e:Event){
//adding the trails
trail = new Trail();
trail.x = ship.x;
trail.y = ship.y;
_cont.addChild(trail);
checkcollision();
}
public function checkcollision(){
for(var _e:int = enemies.length - 1; _e >=0; _e--){
for(var _t:int = _cont.numChildren - 1; _t >=0; _t--){
if(enemies[_e].hitTestObject(_cont.getChildAt(_t))){
enemies[_e].remove();
return;
}
}
}
}
public function removeenemies(_e:Enemy){
for(var i in enemies){
if(enemies[i] == _e){
enemies.splice(_e);
}
}
}
and here is the Enemy class:
public class Enemy extends MovieClip {
private var _speed:Number;
public function Enemy(ypos, speed) {
this.x = 550;
this.y = ypos;
_speed = speed;
addEventListener(Event.ENTER_FRAME, motion);
}
public function motion(e:Event){
this.x -= _speed;
checkoffscreen();
}
public function remove(){
MovieClip(parent).removeenemies(this);
MovieClip(parent).removeChild(this);
removeEventListener(Event.ENTER_FRAME, motion);
return;
}
public function checkoffscreen(){
if(this.x < 0){
MovieClip(parent).removeenemies(this);
MovieClip(parent).removeChild(this);
removeEventListener(Event.ENTER_FRAME, motion);
}
}
}
}
The problem here is after 2 or 3 successful collision detections one goes undetected.. and hence the chances is like 2/3 ...how can i program a 100% successful collision???pls help
I want to recommend not to delete objects from within themselves, instead have a simple isDead boolean inside the the Enemy and in the main class when you loop through enemies check if isDead is set to true, if so then remove the object from the array and delete it from the Stage; no need for removeenemies().
Back to the real problem you're having. You're doing a good job iterating through the list of enemies in reverse since you do expect to remove some objects, that of course results in shift of entries in the array.
It's hard to say what's wrong with this code. I'd say lose removeenemies(). Move any collision testing inside the Enemy and in the Main keep everything in a nice linear update function like so:
public function update() {
for(var i:int = enemies.length - 1; i >=0; i--){
var enemy:Enemy = enemies[i];
enemy.checkCollision(); // Can set isDead = true;
if(enemy.isDead) {
enemies.splice(i);
removeChild(enemy);
}
}
}
Finally I found out the answer.
the problem was with the removeenemies function
replacing splice(_e) wtih splice(_e, 1) solved the problem

hitTestObject issue // remove stage Error #2025

hey :S I`m trying to make 2 things so far but neither work :(
The 1st is to make an Row of 5 Ships that position them selves from the top to left.Then add an Event to make them move down.
But every time i try to make a new Row of 5 new ships ... they position themselves after the last ship from the previous Row.I did think of a way to fix that by waiting the 1st Row of ships to go beyond the stage and then remove them from the stage and splice from the Array but ... when I increase the speed of spawning (when i have 2 rows with 5 ships on the stage or more)that does't work.
And the second error I think is from that fact .... that I have 2 rows at the same time on the stage.
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/removeChild()
at MainClass/doShips()
at MainClass/everyFrame()
I dont know what exactly to paste from the code so i had to push everything in the MainClass of the FLA.fail :D but i did it neatly! so if anyone helped me he would track the code easily
so its a simple FLA.fail with 4 MC and in those 4 MC there is no code
a Bullet
a Ship with colour Yellow
a Ship2 with colour Green so i can see the randomising
and a Player with the class Turret
so the MainClass of the FLA is :
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class MainClass extends MovieClip {
protected var mouseSpeed:Number = 20;
protected var _thePlayer:Turret = new Turret();
protected var shipCount:Number;
protected var shipCount2:Number;
protected var shipArray:Array = new Array();
protected var counter:int = 0;
//variables for bullets
private var shootCooldown:Number = 0; //speed of the fire
private var firing:Boolean = false;//bullets triger
private var numToShoot:int = 1; //bullets
const MAX_COOLDOWN = 10; //bullets timer
protected var _bulletsArray:Array = new Array();
public function MainClass() {
_thePlayer.x = stage.stageWidth/2
_thePlayer.y = stage.stageHeight - _thePlayer.height/2
addChild(_thePlayer)
addEventListener(Event.ENTER_FRAME, everyFrame)
stage.addEventListener(MouseEvent.MOUSE_DOWN, startFire);
stage.addEventListener(MouseEvent.MOUSE_UP, stopFire);
}
private function startFire(ev:MouseEvent) {
firing = true;
}
private function stopFire(ev:MouseEvent) {
firing = false;
}
//every frame do this
protected function everyFrame(ev:Event):void{
//Moving The Turret
moveTheTurret();
//increase the counter every frame
counter++;
if(counter % 70 == 0){
//position the ships on the stage
positionShips();
}
//handle the ships when they are added on the stage
doShips();
//when to fire
updateFire();
//handle the bullets
doBullets();
}
//Moving The Turret
protected function moveTheTurret() {
if (mouseX > _thePlayer.x +15) {
_thePlayer.x += mouseSpeed;
} else if (mouseX < _thePlayer.x - 15) {
_thePlayer.x -= mouseSpeed;
} else {
_thePlayer.x = mouseX;
}
}
//createShips and position them
protected function positionShips() {
shipCount = 3;
shipCount2 = 2;
var gap = 10;
for (var i:int = 0; i < shipCount; i++) {
var s = new Ship();
shipArray.push(s);
}
for (var j:int = 0; j < shipCount2; j++) {
s = new Ship2();
shipArray.push(s);
}
var array:Array=new Array();
while (shipArray.length>0) {
var index:uint = Math.floor(Math.random() * shipArray.length);
array.push(shipArray[index]);
shipArray.splice(index,1);
}
shipArray = array;
//shipsArray has been randomized
for (var k:int = shipArray.length - 1; k >= 0; k--) {
addChild(shipArray[k]);
shipArray[k].x = shipArray[k].width/2 + (shipArray[k].width * k) + (gap*k);
}
}
//move the ships
protected function doShips() {
for (var i:int = shipArray.length - 1; i >= 0; i--) {
shipArray[i].y +=3 //make the Ships fall down
for (var bcount= _bulletsArray.length-1; bcount >= 0; bcount--) {
//if the bullet is touching the ship
if (shipArray[i].hitTestObject(_bulletsArray[bcount])) {
//if we get here it means there`s is a collision
removeChild(_bulletsArray[bcount]);
_bulletsArray.splice(bcount,1);
removeChild(shipArray[i]);
_bulletsArray.splice(i,1);
}
}
//if it gets over 380 remove from stage and splice from the array
if(shipArray[i].y > 380){ // stage.stageHeight)
removeChild(shipArray[i]);
shipArray.splice(i,1);
}
}
}
//when to fire
public function updateFire() {
//if we are currently holding the mouse down
if(firing == true){
fire();
}
//reduce the cooldown by 1 every frame
shootCooldown--;
}
//Shoot bullets
private function fire() {
if (shootCooldown <= 0) {
//reset the cooldown
shootCooldown = MAX_COOLDOWN
for (var i=0; i<numToShoot; i++){
//spown a bullet
var b = new Bullet();
//set the rotation of the bullet
b.rotation = -90
b.x = _thePlayer.x;
b.y = _thePlayer.y;
//add the bullet to the list/Array of _bulletsArray
_bulletsArray.push(b);
//add the bullet to the perent object;
addChild(b);
}
}
}
//handling the bullets
protected function doBullets(){
//make a for loop to iterate all the _bulletsArray on the screen
for (var bcount:int = _bulletsArray.length-1; bcount>=0; bcount--) {
//make the bullets move Up
_bulletsArray[bcount].y -=20;
//if the bullet is beyond the screen remove from the stage and the Array
if(_bulletsArray[bcount].y < 0){
removeChild(_bulletsArray[bcount])
_bulletsArray.splice(bcount,1);
}
}
}
}
}
I dont know how to fix neither of the 2 problems.Would be very thankful for any help!!!
Thanks in advance.

make an object move directly towards a point and stop when it reaches it

How can I make my object stop when it reaches the destination i gave it with my mouse click? The code makes the object move towards the point of a mouse click but I can't seem to find out how to make it stop, because it will almost never pass the specific destination point. :/ Somebody who knows how to accomplish this?
public function onMouseDown(evt:MouseEvent)
{
if (this._character != null)
{
_character.isMoving = false;
_character.dx = 0;
_character.dy = 0;
targetX = mouseX - _character.x;
targetY = mouseY - _character.y;
var angle:Number = Math.atan2(targetY,targetX);
var dx:Number = Math.cos(angle) * _character.speed;
var dy:Number = Math.sin(angle) * _character.speed;
_character.dx = dx;
_character.dy = dy;
_character.isMoving = true;
}
}
public function updateCharacter(e:Event):void
{
if (this._character.isMoving)
{
this._character.x += this._character.dx;
this._character.y += this._character.dy;
}
}
Easiest way to do it would be to calculate the angle to the point you want to stop at each time you move. This value should remain the same if you're moving in a straight line until you pass the point you're trying to stop at, at which point it will change drastically.
Once this happens, simply move your object back to the position it should have stopped at before you render it again.
I've created a demo with source code for you. There's a fair amount of code, so rather than posting everything here you can download the source instead:
http://martywallace.com/testing/gotoPoint.zip
Try this
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class Guest extends MovieClip
{
var walkSpeed:Number = 5;
var oldPosX;
var oldPosY;
public function Guest()
{
stage.addEventListener(MouseEvent.CLICK, walk);
}
function walk(event:MouseEvent):void
{
oldPosX = parent.mouseX;
oldPosY = parent.mouseY;
rotation = Math.atan2(oldPosY - y,oldPosX - x) / Math.PI * 180;
addEventListener(Event.ENTER_FRAME, loop);
}
function loop(event:Event):void
{
// see if you're near the target
var dx:Number = oldPosX - x;
var dy:Number = oldPosY - y;
var distance:Number = Math.sqrt((dx*dx)+(dy*dy));
if (distance<walkSpeed)
{
// if you are near the target, snap to it
x = oldPosX;
y = oldPosY;
removeEventListener(Event.ENTER_FRAME, loop);
}
else
{
x = x+Math.cos(rotation/180*Math.PI)*walkSpeed;
y = y+Math.sin(rotation/180*Math.PI)*walkSpeed;
}
}
}
}
Similar questions have been asked many times.
However, see the code in my answer here that should explain how to move and stop.
Movement of Objects in a simulation