I started playing around with Dart yesterday and thought I would try to make a simple game engine. I'm also new to the canvas element , so I'm sure I'm making a silly mistake somewhere.
Here is my main game loop.
class FunTime {
FunTime(){
gameTime = new Date.now();
gameState = new List<IDrawableGameComponent>();
StartMenu startMenu = new StartMenu();
gameState.add(startMenu);
CanvasElement _canvas = document.query('#canvas');
context = _canvas.getContext('2d');
}
List<IDrawableGameComponent> gameState;
Date gameTime;
CanvasRenderingContext2D context;
}
void main() {
var exit = false;
FunTime game = new FunTime();
Date previousDraw = new Date.now();
while (!exit){
game.gameTime = new Date.now();
//update
game.gameState.last().update(game.gameTime);
int elapsed = game.gameTime.difference(previousDraw).inMilliseconds;
//draw (60 fps)
if(previousDraw == null || elapsed > 16){
//print("Draw Called{$elapsed}");
previousDraw = game.gameTime;
game.gameState.last().draw(game.gameTime, game.context);
}
}
}
Here is the code for the StartMenu code:
class StartMenu implements IDrawableGameComponent{
num positionX = 0;
StartMenu(){
}
void load(){
}
void update(Date gameTime){
//if(positionX < 200)
// positionX++;
}
void draw(Date gameTime, CanvasRenderingContext2D ctx){
ctx.clearRect(0, 0, 800, 600);
ctx.fillStyle = 'black';
ctx.fillRect(0,0,800,600);
ctx.fillStyle = 'white';
ctx.fillRect(positionX, 50, 400, 200);
}
}
For some reason the rectangles are never drawn unless I step through the code. Its almost like the brwoser doesn't have enough time to draw it before the next clear is called. I've tried increasing the draw interval but it doesn't change anything.
Here is how I solved the problem:
class FunTime {
FunTime(){
gameTime = new Date.now();
gameState = new List<IDrawableGameComponent>();
StartMenu startMenu = new StartMenu();
gameState.add(startMenu);
canvas = document.query('#canvas');
context = canvas.getContext('2d');
_previousDraw = 0;
animate(0);
}
animate(int time){
int elapsed = time - _previousDraw;
if( _previousDraw == 0 || elapsed > 16){
this.gameState.last().draw(time, this.context);
_previousDraw = time;
}
this.gameState.last().update(time);
window.webkitRequestAnimationFrame(animate, this.canvas);
}
int _previousDraw;
List<IDrawableGameComponent> gameState;
Date gameTime;
CanvasRenderingContext2D context;
CanvasElement canvas;
}
void main() {
FunTime game = new FunTime();
}
The while loop in the main() method never returns to let the browser thread draw. This is why it only works when you step through it.
This alternative works: using window.setInterval, to call a function every 16ms, but it may not be the correct way for a game loop.
void main() {
var exit = false;
FunTime game = new FunTime();
Date previousDraw = new Date.now();
window.setInterval( () { //note the callback
game.gameTime = new Date.now();
//update
game.gameState.last().update(game.gameTime);
int elapsed = game.gameTime.difference(previousDraw).inMilliseconds;
//draw (60 fps)
if(previousDraw == null || elapsed > 16){
previousDraw = game.gameTime;
game.gameState.last().draw(game.gameTime, game.context);
}
}, 16); //16 ms
}
Related
I have a fairly basic app where you navigate menus and then access videos and demos.
My issue is that when you access a video, it forces you to rotate the screen first.
By using stage.scaleMode = Stage.ScaleMode.NO_SCALE I was able to make it work perfectly on my iPhone 7, but I can't find a way to scale up for iPhone 8 or 10.
I've been trying to use other StageScaleModes, and they work perfectly for the menus but when the screen is rotated, the scale becomes insanely wonky.
It either stays within the original aspect ratio or becomes much to big for the screen.
I've tried using stage.stageWidth and stage.stageHeight to correct this but they never return the correct size.
Any help in either fixing the issue in rotation or making NO_SCALE work would be greatly appreciated.
EDIT:
public function playVideo(path2: String): Function {
path = path2;
var listener: * ;
listener = function (e: MouseEvent = null): void {
stage.addChild(pleaseRotateScreen);
stage.autoOrients = true;
stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGING, orientationChangeListener_Videos);
}
return listener;
}
function orientationChangeListener_Videos(e: StageOrientationEvent) {
if (e.afterOrientation == StageOrientation.ROTATED_RIGHT || e.afterOrientation == StageOrientation.ROTATED_LEFT) {
stage.removeEventListener(StageOrientationEvent.ORIENTATION_CHANGING, orientationChangeListener_Videos);
stage.autoOrients = false;
stage.removeChild(pleaseRotateScreen);
startVideo();
}
}
EDIT2
public function startVideo(): void { //bring up the video UI.
stage.displayState = StageDisplayState.FULL_SCREEN;
headerTextField = new TextField();
headerTextField.autoSize = TextFieldAutoSize.LEFT;
var theFont = new BrownReg();
var rectClip: Sprite = new Sprite();
headerTextField.autoSize = "left";
//headerTextField.text = pageClip2.uiText;
headerTextField.text = "Stage Width: " + stage.width + " Stage.Height: " + stage.stageHeight;
headerTextField.selectable = false;
backPlate = new MovieClip;
backPlate.graphics.beginFill(0x000000);
backPlate.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
backPlate.graphics.endFill();
overlay = new blackOverlay;
video_UI.addChild(overlay);
overlay.addEventListener(MouseEvent.CLICK, bringUpVideoUI);
mcScroll.addChild(backPlate);
TweenLite.to(menu_clip, .4, { alpha: 0, ease: Expo.easeOut });
TweenLite.to(screen_clip, .4, { alpha: 0, ease: Expo.easeOut });
TweenLite.to(pageClip, .4, { alpha: 0, ease: Expo.easeOut });
TweenLite.to(mcScroll, .4, { alpha: 0, ease: Expo.easeOut });
TweenLite.to(topbar_clip, .4, { alpha: 0, ease: Expo.easeOut });
video_UI.addChild(gradientVid);
gradientVid.y = 750 - 100;
X_UI = new videoX;
X_UI.x = (1254+24); X_UI.y = (678+24);
video_UI.addChild(X_UI);
X_UI.addEventListener(MouseEvent.CLICK, closeVideo);
pauseUI = new MovieClip;
pauseUI.addChild(pauseClip);
pauseUI.x = (140+24); pauseUI.y = (672+30);
video_UI.addChild(pauseUI);
pauseUI.addEventListener(MouseEvent.CLICK, pauseVid);
jumpBackUI = new mcFastForward;
jumpBackUI.rotation = 180;
jumpBackUI.x = (32+30); jumpBackUI.y = (672+30);
video_UI.addChild(jumpBackUI);
jumpBackUI.addEventListener(MouseEvent.CLICK, seekBack);
jumpForwardUI = new mcFastForward;
jumpForwardUI.x = (248+30); jumpForwardUI.y = (672+30);
video_UI.addChild(jumpForwardUI);
jumpForwardUI.addEventListener(MouseEvent.CLICK, seekForward);
var f: TextFormat = new TextFormat();
headerTextField.x = 32; headerTextField.y = 60;
f.size = 48;
f.font = theFont.fontName;
f.color = 0xffffff;
headerTextField.embedFonts = true;
headerTextField.setTextFormat(f);
video_UI.addChild(headerTextField);
video_UI.alpha = 0;
videoRect.width = stage.stageWidth;
videoRect.height = stage.stageHeight;
//videoRect.scaleX = videoRect.scaleY;
initVideo();
bringUpVideoUI();
}
Before Rotate
After Rotate
Edit 3:
public function initVideo(): void {
var obj: MovieClip = new MovieClip();
var nc: NetConnection = new NetConnection();
nc.connect(null);
netstream = new NetStream(nc);
netstream.client = obj;
obj.onMetaData = onMetaData;
stageVideo = stage.stageVideos[0];
stageVideo.addEventListener(StageVideoEvent.RENDER_STATE, onRender);
stageVideo.attachNetStream(netstream);
netstream.play(path);
netstream.seek(0);
netstream.removeEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
netstream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
netstream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, doAsyncError);
netstream.addEventListener(NetStatusEvent.NET_STATUS, doNetStatus);
netstream.addEventListener(IOErrorEvent.IO_ERROR, doIOError);
if (netstream != null) {
netstream.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, doAsyncError);
netstream.removeEventListener(NetStatusEvent.NET_STATUS, doNetStatus);
netstream.removeEventListener(IOErrorEvent.IO_ERROR, doIOError);
}
}
//Video Functions
public function shrinkVideo() { }
public function enlargeVideo() { }
protected function doSecurityError(evt: SecurityErrorEvent): void { trace("AbstractStream.securityError:" + evt.text); }
protected function doIOError(evt: IOErrorEvent): void { trace("AbstractScreem.ioError:" + evt.text); }
protected function doAsyncError(evt: AsyncErrorEvent) { trace("AsyncError:" + evt.text); }
protected function doNetStatus(evt: NetStatusEvent): void { }
private function onMetaData(e: Object): void { duration = e.duration; }
private function onRender(e: StageVideoEvent): void {
if(videoDemo == true){
addEventListener(Event.ENTER_FRAME, onEnterFrame);
cl.addEventListener(MouseEvent.CLICK, _handleClick); //add the clickforward to the the rectangle.
}
stageVideo.viewPort = videoRect;
}
private function netStatusHandler(e: NetStatusEvent): void { //get the end of a video
if (e.info.code == "NetStream.Play.Stop") {
if (demo == true) {
netstream.play(path); //loop the video if its in a demo
} else if (videoDemo == true) {
returnFromDemo();
}else{
exitVid();
}
}
}
When developing a multiscreen game or app, developers need to read device's screen size to correctly rescale and reorganise screen elements.
These sizing issues can be very frustrating, especially as behavior is not the same across OSes and devices.
My personal preference is to always have my apps run in
fullscreenMode = true / aspectRatio = portrait / autoOrients = false, only.
If there is a need to redraw/resize stuff based on a change in orientation, then a handler should be able to 'fake' it, rather than actually modifying the stage.
Okay, so When I run my loader.swf, it's loads my game.swf perfectly fine. But when I stimulate download, at exactly 70%, My music of game.swf starts playing and it shows following errors:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at GAME_fla::MainTimeline/frame11()
And
Error #2044: Unhandled IOErrorEvent:. text=Error #2036: Load Never Completed.
The game works perfectly fine when loaded normally. This issue persists when I upload it online and check if it's working. It doesn't. My loader works well for other swf files. How to solve this?
Code of layer 1, frame 11
import flash.media.SoundChannel;
var bgmusic2: loverswalk = new loverswalk;
var bgmusic: spring = new spring;
var forestmusic: NatureAmbiance = new NatureAmbiance;
var cafemusic: cafeteria1 = new cafeteria1;
var shopmusic: pamfluiteloop = new pamfluiteloop;
var cash: CashRegisterChaChing = new CashRegisterChaChing;
var beeps: beep = new beep;
var musicboxsound: BlaclRockShooterMusicBox = new BlaclRockShooterMusicBox;
var failsound: fail = new fail;
var stgup: stageup = new stageup;
var talkbg: talkbag = new talkbag;
var ca: correct = new correct;
var myChannel: SoundChannel = new SoundChannel();
var bg: SoundChannel = new SoundChannel();
var mb: SoundChannel = new SoundChannel();
var myChanneltalk: SoundChannel = new SoundChannel();
var lastpositionbg: Number = 0;
var moodshop = 0;
var dilbgrun = 0;
var alertsound: alert = new alert;
Layer 2, frame 20
var hp: int = 100;
var day: int = 1;
var week: int = 1;
var money: Number = 0;
var pendants: int = 0;
var bracelets: int = 0;
var comics: int = 0;
var poetrys: int = 0;
var tshirts: int = 0;
var named: String = "Driver";
var age: int = 17;
var reply: int = 0;
var dilrun: String = " ";
var ncpvar: int = -1;
var ncpvare: int = -1;
var ncpvarm: int = -1;
var flavie_stage: int = 0;
var shannon_stage: int = 0;
var vivette_stage: int = 0;
var audrey_stage: int = 0;
var gabriel_stage: int = 0;
var toret: int = 0;
function refresh1(event: Event): void {
Object(this).bar.hp_text.text = String(hp);
Object(this).bar.day_text.text = String(day);
Object(this).bar.week_text.text = String(week);
Object(this).bar.money_text.text = String(money);
}
function bedbtn(event: MouseEvent): void {
alert_mc.gotoAndStop("Alert");
alert_mc.alert_mc.alert_text.text = "You slept a night and gained a massive 100 HP. Enjoy!";
hp = 100;
day = day + 1;
if (day == 8) {
day = 1;
week = week + 1;
}
}
function woman(event: MouseEvent): void {
if (event.target == audrey_btn) {
if (hp >= 30) {
hp = hp - 30;
dilrun = "Audrey";
dial_mc.gotoAndPlay("Dialogue");
} else {
alertsound.play();
alert_mc.gotoAndStop("Alert");
alert_mc.alert_mc.alert_text.text = "Go get some more HP silly!";
}
}
if (event.target == shannon_btn) {
if (hp >= 30) {
hp = hp - 30;
dilrun = "Shannon";
dial_mc.gotoAndPlay("Dialogue");
} else {
alertsound.play();
alert_mc.gotoAndStop("Alert");
alert_mc.alert_mc.alert_text.text = "Go get some more HP silly!";
}
}
if (event.target == vivette_btn) {
if (hp >= 30) {
hp = hp - 30;
dilrun = "Vivette";
dial_mc.gotoAndPlay("Dialogue");
} else {
alertsound.play();
alert_mc.gotoAndStop("Alert");
alert_mc.alert_mc.alert_text.text = "Go get some more HP silly!";
}
}
if (event.target == gabriel_btn) {
if (hp >= 30) {
hp = hp - 30;
dilrun = "Gabriel";
dial_mc.gotoAndPlay("Dialogue");
} else {
alertsound.play();
alert_mc.gotoAndStop("Alert");
alert_mc.alert_mc.alert_text.text = "Go get some more HP silly!";
}
}
if (event.target == flavie_btn) {
if (hp >= 30) {
hp = hp - 30;
dilrun = "Flavie";
dial_mc.gotoAndPlay("Dialogue");
} else {
alertsound.play();
alert_mc.gotoAndStop("Alert");
alert_mc.alert_mc.alert_text.text = "Go get some more HP silly!";
}
}
}
function NCP(event: MouseEvent): void {
if (event.target == odile_btn) {
if (hp >= 10) {
hp = hp - 10;
dilrun = "Odile";
dial_mc.gotoAndPlay("Dialogue");
} else {
alertsound.play();
alert_mc.gotoAndStop("Alert");
alert_mc.alert_mc.alert_text.text = "You need more HP to talk to Odile.";
}
}
if (event.target == elias_btn) {
if (hp >= 10) {
hp = hp - 10;
dilrun = "Elias";
dial_mc.gotoAndPlay("Dialogue");
} else {
alertsound.play();
alert_mc.gotoAndStop("Alert");
alert_mc.alert_mc.alert_text.text = "You need more HP to talk to Elias.";
}
}
if (event.target == mikel_btn) {
if (hp >= 10) {
hp = hp - 10;
dilrun = "Mikel";
dial_mc.gotoAndPlay("Dialogue");
} else {
alertsound.play();
alert_mc.gotoAndStop("Alert");
alert_mc.alert_mc.alert_text.text = "You need more HP to talk to Mikel.";
}
}
}
function buy(event: MouseEvent): void {
if (event.target == gifts_btn) {
Object(this).menu_mc.gotoAndStop("Shop");
}
if (event.target == buy_food_btn) {
Object(this).menu_mc.gotoAndStop("Cafe");
}
}
function job(event: MouseEvent): void {
alertsound.play();
alert_mc.gotoAndStop("Alert");
if (event.target == job1_btn) {
if (hp >= 40) {
hp = hp - 40;
money = money + 30;
alert_mc.alert_mc.alert_text.text = "You earnt 30 for 40 HP";
} else if (hp < 40) {
alert_mc.alert_mc.alert_text.text = "You don't have 40 HP to that. Better sleep or eat to gain more HP.";
}
}
if (event.target == job2_btn) {
if (hp >= 30) {
hp = hp - 30;
money = money + 20;
alert_mc.alert_mc.alert_text.text = "You earnt 20 for 30 HP";
} else if (hp < 30) {
alert_mc.alert_mc.alert_text.text = "You don't have 30 HP to that. Better sleep or eat to gain more HP.";
}
}
if (event.target == job3_btn) {
if (hp >= 20) {
hp = hp - 20;
money = money + 10;
alert_mc.alert_mc.alert_text.text = "You earnt 10 for 20 HP";
} else if (hp < 20) {
alert_mc.alert_mc.alert_text.text = "You don't have 20 HP to that. Better sleep or eat to gain more HP.";
}
}
}
If I add them, other frames are not being able to access those variables.
Loader code before:
var myrequest: URLRequest = new URLRequest("GAME.swf");
var myloader: Loader = new Loader();
myloader.load(myrequest);
myloader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progresshandler);
function progresshandler(myevent: ProgressEvent): void {
var myprogress: Number = myevent.target.bytesLoaded / myevent.target.bytesTotal;
bar_mc.scaleX = myprogress;
percentage_text.text = Math.round(myprogress * 100) + "%";
}
myloader.contentLoaderInfo.addEventListener(Event.COMPLETE, finished);
function finished(myevent: Event): void {
addChild(myloader);
removeChild(percentage_text);
removeChild(bar_mc);
removeChild(background_mc);
}
Loader Code After:
var myrequest: URLRequest = new URLRequest("GAME.swf");
import flash.net.URLRequest;
import flash.display.MovieClip;
import flash.events.Event;
var myloader: Loader = new Loader();
myloader.load(myrequest);
function progresshandler(myevent: ProgressEvent): void {
var myprogress: Number = myevent.target.bytesLoaded / myevent.target.bytesTotal;
bar_mc.scaleX = myprogress;
percentage_text.text = Math.round(myprogress * 100) + "%";
}
myloader.contentLoaderInfo.addEventListener(Event.INIT, finished);
myloader.contentLoaderInfo.addEventListener(Event.COMPLETE, completes);
function finished(myevent: Event): void {
addChild(myloader);
removeChild(percentage_text);
removeChild(bar_mc);
removeChild(background_mc);
}
function completes(myevent: Event): void {
var loaderInfo: LoaderInfo = myevent.target as LoaderInfo;
var swf: Object = loaderInfo.content;
swf.play();
}
Maybe you should give a try to this event: ADDED_TO_STAGE.
The ADDED_TO_STAGE event is triggered when an object is added to stage (very curious name and correlation), that is when you execute an addChild method.
Try to listen to this event in your Main class of your external SWF, so, no code will be executed before you add this respective object to stage (now you can hear the music even during the load process.
Follow some example:
package
{
import flash.display.Sprite;
import flash.events.Event;
public class TheMainClassOfYourExternalSWF extends Sprite
{
public function TheMainClassOfYourExternalSWF()
{
addEventListener(Event.ADDED_TO_STAGE, initHandler);
}
private function initHandler(event:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, initHandler);
trace('this is the stage:', stage);
trace('this is my parent:', this.parent);
// here you start to include your logic
}
}
}
if you are using a FLA file and adding your code using timeline, you can try:
addEventListener(Event.ADDED_TO_STAGE, initHandler);
function initHandler(event:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, initHandler);
// here you start to include your logic, call your functions, initialise your instances...
}
When loading an external swf there are 2 things to be aware of.
First the first frame of the loaded swf start playing when the Event.INIT triggers not when the Event.COMPLETE triggers. The event init triggers when the first frame can be played while the complete triggers when the whole swf is loaded.
Second stage or root is only available in the loaded swf when it had be added to a display list that is added to the stage. A loaded swf has no stage or root when the Event.INIT triggers so the first frame of the swf should not have any reference to stage or root.
If you do not use a document class with your swf then make your first frame empty with just a stop() then once loaded and added to a display list make your swf go to frame 2 where you have all your code.
I have a memory game program and when the timer runs out, I want it to go to frame 3 where it displays the "game failed" page.
I have it all set up, except when the game runs out of time, the frame just appears to overlap the original frame, instead of going to a completely separate page.
Can anyone help me?
Here is my code:
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.utils.Timer;
import flash.display.MovieClip;
import flash.text.TextField;
public class MemoryGame extends MovieClip{
private var firstTile:cards;
private var secondTile:cards;
private var pauseTimer:Timer;
private var score:int;
private var cardCount:int;
var seconds:Number;
var minutes:Number;
var numberDeck:Array = new Array(1,1,2,2,3,3,4,4,5,5,6,6);
public function MemoryGame(){
//TIMER FUNCTION
var levelTimer:Timer = new Timer(1000, 180);
levelTimer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler);
levelTimer.addEventListener(TimerEvent.TIMER, timerHandler);
// LEVEL FUNCTION
easyBtn.addEventListener(MouseEvent.CLICK, easyButtonClicked);
medBtn.addEventListener(MouseEvent.CLICK, medButtonClicked);
hardBtn.addEventListener(MouseEvent.CLICK, hardButtonClicked);
score = 0;
txtScore.text=""+score;
//Level button events
function easyButtonClicked(e:MouseEvent):void{
removeChild(levelText);
trace("easy button clicked!");
seconds = 0;
minutes = 1;
txtTime.text = "1:00";
levelTimer.start();
setupTiles();
}
function medButtonClicked(e:MouseEvent):void{
removeChild(levelText);
trace("medium button clicked!");
seconds = 30;
minutes = 0;
txtTime.text = "0:30";
levelTimer.start();
setupTiles();
}
function hardButtonClicked(e:MouseEvent):void{
removeChild(levelText);
trace("hard button clicked!");
seconds = 15;
minutes = 0;
txtTime.text = "0:15";
levelTimer.start();
setupTiles();
}
//Timer handlers
function timerHandler(e:TimerEvent):void {
if (seconds > 00) {
seconds -=1;
}
else {
if (minutes > 0) {minutes -=1;seconds = 59;}
}
txtTime.text = minutes+":"+(seconds >= 10 ? seconds : "0"+seconds);
}
function timerCompleteHandler(e:TimerEvent):void {
e.target.reset();
e.target.stop();
trace("game over!");
}
//Tiles set up
function setupTiles(){
for(x=1; x<=4; x++) {
for (y=1; y<=3; y++){
var randomCard = Math.floor(Math.random()*numberDeck.length);
var tile:cards = new cards();
tile.card = numberDeck[randomCard];
numberDeck.splice(randomCard,1);
tile.gotoAndStop(9);
tile.x = (x-1) * 150;
tile.y = (y-1) * 200;
tile.addEventListener(MouseEvent.CLICK,tileClicked);
addChild(tile);
cardCount = cardCount + 1
}
}
}
}
public function tileClicked(event:MouseEvent) {
var clicked:cards = (event.currentTarget as cards);
if (firstTile == null){
firstTile = clicked;
firstTile.gotoAndStop(clicked.card);
}
else if (secondTile == null && firstTile != clicked){
secondTile = clicked;
secondTile.gotoAndStop(clicked.card);
if (firstTile.card == secondTile.card){
pauseTimer = new Timer(1000, 1);
pauseTimer.addEventListener(TimerEvent.TIMER_COMPLETE,removeCards);
pauseTimer.start();
}
else {
pauseTimer = new Timer(1000, 1);
pauseTimer.addEventListener(TimerEvent.TIMER_COMPLETE,resetCards);
pauseTimer.start();
}
}
if (seconds == 0){
this.gotoAndStop(2);
pauseTimer.stop();
//levelTimer.stop();
}
}
public function resetCards(event:TimerEvent) {
firstTile.gotoAndStop(9);
secondTile.gotoAndStop(9);
firstTile = null;
secondTile = null;
pauseTimer.removeEventListener(TimerEvent.TIMER_COMPLETE,resetCards);
score = score - 2;
txtScore.text=""+score;
}
public function removeCards(event:TimerEvent){
removeChild(firstTile);
removeChild(secondTile);
firstTile = null;
secondTile = null;
pauseTimer.removeEventListener(TimerEvent.TIMER_COMPLETE,removeCards);
score = score + 10;
txtScore.text=""+score;
cardCount = cardCount - 2;
trace("Cardcount: " + cardCount);
if (cardCount == 0){
this.gotoAndStop(2);
txtFinalScore.text=" "+score;
pauseTimer.stop();
}
}
}
}
Thank you so much!
When you add an object using addChild(object) it isn't associated with keyframes along the timeline.
So what you need to do is rather than jumping to frame 2, removeChild(object) or object.visible = false all children you don't want and addChild(object) your 'out of time' assets.
A good work ethic is to create destroy() functions that remove and null any unwanted assets. This way you can easily remove unwanted items and free up memory.
I'm building a game in AS3 based off of Gary Rosenzweig's latest Actionscript 3 book. It has a game timer issue, not just mine but his demo too, that I can't figure out.
The game is like Asteroids where four rocks are placed in the corners of the stage at the beginning and then start moving randomly around the stage. The problem is the timer used is started the moment that the flash file starts not the moment the player clicks the start button. So if you are on the start screen for 5 seconds before you click play when the game actually begins the rocks are where they would be after 5 seconds of play, which could be right over the player.
I've posted the parts of the code that I think apply. Could someone please tell me how to modify this so that when the player actually starts the game the rocks start in their proper places. I'm pretty sure it's the last function that I've included that is the problem but I've included other related parts to give you a more complete picture.
package {
import flash.display.*;
import flash.events.*;
import flash.events.TouchEvent;
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;
import flash.text.*;
import flash.utils.getTimer;
import flash.utils.Timer;
import flash.geom.Point;
import flash.net.SharedObject;
import flash.media.Sound;
import flash.media.SoundMixer;
import flash.media.SoundTransform;
import flash.media.SoundChannel;
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
public class VirusDefender extends MovieClip {
static const shipRotationSpeed:Number = .1;
static const rockSpeedStart:Number = .03;
static const rockSpeedIncrease:Number = .01;
static const missileSpeed:Number = .2;
static const thrustPower:Number = .15;
static const shipRadius:Number = 20;
static const startingShips:uint = 3;
// game objects
private var ship:Ship;
private var rocks:Array;
private var missiles:Array;
// animation timer
private var lastTime:uint;
// arrow keys
private var rightArrow:Boolean = false;
private var leftArrow:Boolean = false;
private var upArrow:Boolean = false;
// ship velocity
private var shipMoveX:Number;
private var shipMoveY:Number;
// timers
private var delayTimer:Timer;
private var shieldTimer:Timer;
// game mode
private var gameMode:String;
private var shieldOn:Boolean;
// ships and shields
private var shipsLeft:uint;
private var shieldsLeft:uint;
private var shipIcons:Array;
private var shieldIcons:Array;
private var scoreDisplay:TextField;
// score and level
private var gameScore:Number;
private var gameLevel:uint;
// sprites
private var gameObjects:Sprite;
private var scoreObjects:Sprite;
var gameBackground:GameBackground = new GameBackground();
// sounds
var sndFire:fire_sound;
var sndFireChannel:SoundChannel;
var sndThruster:thruster_sound;
var sndThrusterChannel:SoundChannel;
var sndShield:shield_sound;
var sndShieldChannel:SoundChannel;
var sndExplosion:explosion_sound;
var sndExplosionChannel:SoundChannel;
var sndBubble:bubble_sound;
var sndBubbleChannel:SoundChannel;
// start the game
public function startSpaceRocks() {
// set up sprites
addChild(gameBackground);
setChildIndex(gameBackground,0); // I added this
gameObjects = new Sprite();
addChild(gameObjects);
scoreObjects = new Sprite();
addChild(scoreObjects);
// reset score objects
gameLevel = 1;
shipsLeft = startingShips;
gameScore = 0;
createShipIcons();
createScoreDisplay();
// set up listeners
trace("add moveGameObjects event listener");
addEventListener(Event.ENTER_FRAME,moveGameObjects);
leftButton.addEventListener(TouchEvent.TOUCH_OVER,leftPress);
leftButton.addEventListener(TouchEvent.TOUCH_OUT,leftRelease);
rightButton.addEventListener(TouchEvent.TOUCH_OVER,rightPress);
rightButton.addEventListener(TouchEvent.TOUCH_OUT,rightRelease);
thrusterButton.addEventListener(TouchEvent.TOUCH_OVER,thrusterPress);
thrusterButton.addEventListener(TouchEvent.TOUCH_OUT,thrusterRelease);
shieldButton.addEventListener(TouchEvent.TOUCH_OVER,shieldPress);
fireButton.addEventListener(TouchEvent.TOUCH_OVER,firePress);
// Left Button
function leftPress(event:TouchEvent):void{
leftArrow = true;
}
function leftRelease(event:TouchEvent):void{
leftArrow = false;
}
// Right button
function rightPress(event:TouchEvent):void{
rightArrow = true;
}
function rightRelease(event:TouchEvent):void{
rightArrow = false;
}
// Thruster button
function thrusterPress(event:TouchEvent):void{
sndThruster=new thruster_sound();
sndThrusterChannel=sndThruster.play();
upArrow = true;
if (gameMode == "play") ship.gotoAndStop(2);
}
function thrusterRelease(event:TouchEvent):void{
sndThrusterChannel.stop();
upArrow = false;
if (gameMode == "play") ship.gotoAndStop(1);
}
// Fire button
function firePress(event:TouchEvent):void{
sndFire=new fire_sound();
sndFireChannel=sndFire.play();
newMissile();
}
// Shield button
function shieldPress(event:TouchEvent):void{
startShield(false);
}
// start
gameMode = "delay";
trace("gameMode - delay");
shieldOn = false;
missiles = new Array();
trace("nextRockWave fired");
nextRockWave(null);
newShip(null);
}
// SCORE OBJECTS
// draw number of ships left
public function createShipIcons() {
shipIcons = new Array();
for(var i:uint=0;i<shipsLeft;i++) {
var newShip:ShipIcon = new ShipIcon();
newShip.x = 165+i*25; //165
newShip.y = 273; //273
scoreObjects.addChild(newShip);
shipIcons.push(newShip);
}
}
// draw number of shields left
public function createShieldIcons() {
shieldIcons = new Array();
for(var i:uint=0;i<shieldsLeft;i++) {
var newShield:ShieldIcon = new ShieldIcon();
newShield.x = 310-i*25; //530
newShield.y = 273; //15
scoreObjects.addChild(newShield);
shieldIcons.push(newShield);
}
}
// put the numerical score at the upper right
public function createScoreDisplay() {
updateScore();
}
// new score to show
public function updateScore() {
score.text = addCommaInNumber(gameScore);
}
// remove a ship icon
public function removeShipIcon() {
scoreObjects.removeChild(shipIcons.pop());
}
// remove a shield icon
public function removeShieldIcon() {
scoreObjects.removeChild(shieldIcons.pop());
}
// remove the rest of the ship icons
public function removeAllShipIcons() {
while (shipIcons.length > 0) {
removeShipIcon();
}
}
// remove the rest of the shield icons
public function removeAllShieldIcons() {
while (shieldIcons.length > 0) {
removeShieldIcon();
}
}
// SHIP CREATION AND MOVEMENT
// create a new ship
public function newShip(event:TimerEvent) {
// if ship exists, remove it
if (ship != null) {
gameObjects.removeChild(ship);
ship = null;
}
// no more ships
if (shipsLeft < 1) {
endGame();
return;
}
// create, position, and add new ship
ship = new Ship();
ship.gotoAndStop(1);
ship.x = 240; //275
ship.y = 160; //200
ship.rotation = -90;
ship.shield.visible = false;
gameObjects.addChild(ship);
// set up ship properties
shipMoveX = 0.0;
shipMoveY = 0.0;
gameMode = "play";
// set up shields
shieldsLeft = 3;
createShieldIcons();
// all lives but the first start with a free shield
if (shipsLeft != startingShips) {
startShield(true);
sndShield=new shield_sound();
sndShieldChannel=sndShield.play();
}
}
// animate ship
public function moveShip(timeDiff:uint) {
// rotate and thrust
if (leftArrow) {
ship.rotation -= shipRotationSpeed*timeDiff;
} else if (rightArrow) {
ship.rotation += shipRotationSpeed*timeDiff;
} else if (upArrow) {
shipMoveX += Math.cos(Math.PI*ship.rotation/180)*thrustPower;
shipMoveY += Math.sin(Math.PI*ship.rotation/180)*thrustPower;
}
// move
ship.x += shipMoveX;
ship.y += shipMoveY;
// wrap around screen
if ((shipMoveX > 0) && (ship.x > 470)) {
ship.x -= 490;
}
if ((shipMoveX < 0) && (ship.x < -20)) {
ship.x += 500;
}
if ((shipMoveY > 0) && (ship.y > 320)) {
ship.y -= 340;
}
if ((shipMoveY < 0) && (ship.y < -20)) {
ship.y += 340;
}
}
// remove ship
public function shipHit() {
gameMode = "delay";
ship.gotoAndPlay("explode");
sndExplosion=new explosion_sound();
sndExplosionChannel=sndExplosion.play();
removeAllShieldIcons();
delayTimer = new Timer(2000,1);
delayTimer.addEventListener(TimerEvent.TIMER_COMPLETE,newShip);
delayTimer.start();
removeShipIcon();
shipsLeft--;
}
// turn on shield for 3 seconds
public function startShield(freeShield:Boolean) {
if (shieldsLeft < 1) return; // no shields left
if (shieldOn) return; // shield already on
// turn on shield and set timer to turn off
ship.shield.visible = true;
sndShield=new shield_sound();
sndShieldChannel=sndShield.play();
shieldTimer = new Timer(3000,1);
shieldTimer.addEventListener(TimerEvent.TIMER_COMPLETE,endShield);
shieldTimer.start();
// update shields remaining
if (!freeShield) {
removeShieldIcon();
shieldsLeft--;
}
shieldOn = true;
}
// turn off shield
public function endShield(event:TimerEvent) {
ship.shield.visible = false;
shieldOn = false;
}
// ROCKS
// create a single rock of a specific size
public function newRock(x,y:int, rockType:String) {
trace("newRock fired");
// create appropriate new class
var newRock:MovieClip;
var rockRadius:Number;
if (rockType == "Big") {
newRock = new Rock_Big();
rockRadius = 35;
} else if (rockType == "Medium") {
newRock = new Rock_Medium();
rockRadius = 20;
} else if (rockType == "Small") {
newRock = new Rock_Small();
rockRadius = 10;
}
// choose a random look
newRock.gotoAndStop(Math.ceil(Math.random()*3));
// set start position
newRock.x = x;
newRock.y = y;
// set random movement and rotation
var dx:Number = Math.random()*2.0-1.0;
var dy:Number = Math.random()*2.0-1.0;
var dr:Number = Math.random();
// add to stage and to rocks list
gameObjects.addChild(newRock);
setChildIndex(gameObjects,1); // I added this
rocks.push({rock:newRock, dx:dx, dy:dy, dr:dr, rockType:rockType, rockRadius: rockRadius});
}
// create four rocks
public function nextRockWave(event:TimerEvent) {
rocks = new Array();
newRock(30,30,"Big"); //100 100
newRock(30,290,"Big"); // 100 300
newRock(450,30,"Big"); // 450 100
newRock(450,290,"Big"); // 450 300
gameMode = "play";
}
// animate all rocks
public function moveRocks(timeDiff:uint) {
for(var i:int=rocks.length-1;i>=0;i--) {
// move the rocks
var rockSpeed:Number = rockSpeedStart + rockSpeedIncrease*gameLevel;
rocks[i].rock.x += rocks[i].dx*timeDiff*rockSpeed;
rocks[i].rock.y += rocks[i].dy*timeDiff*rockSpeed;
// rotate rocks
rocks[i].rock.rotation += rocks[i].dr*timeDiff*rockSpeed;
// wrap rocks
if ((rocks[i].dx > 0) && (rocks[i].rock.x > 470)) {
rocks[i].rock.x -= 490;
}
if ((rocks[i].dx < 0) && (rocks[i].rock.x < -20)) {
rocks[i].rock.x += 490;
}
if ((rocks[i].dy > 0) && (rocks[i].rock.y > 325)) {
rocks[i].rock.y -= 345;
}
if ((rocks[i].dy < 0) && (rocks[i].rock.y < -25)) {
rocks[i].rock.y += 345;
}
}
}
public function rockHit(rockNum:uint) {
// create two smaller rocks
sndBubble=new bubble_sound();
sndBubbleChannel=sndBubble.play();
if (rocks[rockNum].rockType == "Big") {
newRock(rocks[rockNum].rock.x,rocks[rockNum].rock.y,"Medium");
newRock(rocks[rockNum].rock.x,rocks[rockNum].rock.y,"Medium");
} else if (rocks[rockNum].rockType == "Medium") {
newRock(rocks[rockNum].rock.x,rocks[rockNum].rock.y,"Small");
newRock(rocks[rockNum].rock.x,rocks[rockNum].rock.y,"Small");
}
// remove original rock
gameObjects.removeChild(rocks[rockNum].rock);
rocks.splice(rockNum,1);
}
// MISSILES
// create a new Missile
public function newMissile() {
// create
var newMissile:Missile = new Missile();
// set direction
newMissile.dx = Math.cos(Math.PI*ship.rotation/180);
newMissile.dy = Math.sin(Math.PI*ship.rotation/180);
// placement
newMissile.x = ship.x + newMissile.dx*shipRadius;
newMissile.y = ship.y + newMissile.dy*shipRadius;
// add to stage and array
gameObjects.addChild(newMissile);
missiles.push(newMissile);
}
// animate missiles
public function moveMissiles(timeDiff:uint) {
for(var i:int=missiles.length-1;i>=0;i--) {
// move
missiles[i].x += missiles[i].dx*missileSpeed*timeDiff;
missiles[i].y += missiles[i].dy*missileSpeed*timeDiff;
// moved off screen
if ((missiles[i].x < 0) || (missiles[i].x > 485) || (missiles[i].y < 0) || (missiles[i].y > 325)) {
gameObjects.removeChild(missiles[i]);
delete missiles[i];
missiles.splice(i,1);
}
}
}
// remove a missile
public function missileHit(missileNum:uint) {
gameObjects.removeChild(missiles[missileNum]);
missiles.splice(missileNum,1);
}
// GAME INTERACTION AND CONTROL
public function moveGameObjects(event:Event) {
// get timer difference and animate
var timePassed:uint = getTimer() - lastTime;
lastTime += timePassed;
moveRocks(timePassed);
if (gameMode != "delay") {
moveShip(timePassed);
}
moveMissiles(timePassed);
checkCollisions();
}
// look for missiles colliding with rocks
public function checkCollisions() {
// loop through rocks
rockloop: for(var j:int=rocks.length-1;j>=0;j--) {
// loop through missiles
missileloop: for(var i:int=missiles.length-1;i>=0;i--) {
// collision detection
if (Point.distance(new Point(rocks[j].rock.x,rocks[j].rock.y),
new Point(missiles[i].x,missiles[i].y))
< rocks[j].rockRadius) {
// remove rock and missile
rockHit(j);
missileHit(i);
// add score
gameScore += 10;
updateScore();
// break out of this loop and continue next one
continue rockloop;
}
}
// check for rock hitting ship
if (gameMode == "play") {
if (shieldOn == false) { // only if shield is off
if (Point.distance(new Point(rocks[j].rock.x,rocks[j].rock.y),
new Point(ship.x,ship.y))
< rocks[j].rockRadius+shipRadius) {
// remove ship and rock
shipHit();
rockHit(j);
}
}
}
}
// all out of rocks, change game mode and trigger more
if ((rocks.length == 0) && (gameMode == "play")) {
gameMode = "betweenlevels";
gameLevel++; // advance a level
levelTextBox.text = "Infection: " + gameLevel;
delayTimer = new Timer(2000,1);
delayTimer.addEventListener(TimerEvent.TIMER_COMPLETE,nextRockWave);
delayTimer.start();
}
}
public function endGame() {
// remove all objects and listeners
removeChild(gameObjects);
removeChild(scoreObjects);
removeChild(gameBackground);
gameObjects = null;
scoreObjects = null;
removeEventListener(Event.ENTER_FRAME,moveGameObjects);
gameMode = "gameOver";
gotoAndStop("gameover");
}
/***** ADD COMMAS TO NUMBERS *******/
function addCommaInNumber (number : Number) : String
{
var integer : String = "" ;
var fraction : String = "" ;
var string : String = number.toString();
var array : Array = string.split(".");
var regex : RegExp = /(\d+)(\d{3})/;
integer = array[0];
while( regex.test(integer) )
{
integer = integer.replace(regex,'$1' + ',' + '$2');
}
if (array[1])
{ fraction = integer.length > 0 ? '.' + array[1] : ''; }
return integer + fraction;
}
}
}
The part of code you thought applied to your problem is incorrect.
A timer can be started along with it's declaration as :
private var myTimer:Timer = new Timer(delay, repeat);
But since you are not initiating the timer at the time of declaration (as seen in you snippet)
// timers
private var delayTimer:Timer;
private var shieldTimer:Timer;
There must be some other function where it would be initiated. Move the action of initiating the timer to whichever place you want to start the timer. For eg : into startspacerocks() function
If that is not the problem, please post the relevant code that applies to your problem.
EDIT:
Well I think your answer lies in the moveGameObjects function.
Try modifying the function as follows:
// GAME INTERACTION AND CONTROL
public function moveGameObjects(event:Event) {
//Current Time
var currentTime:uint = getTimer();
//Initiate lastTime
if(lastTime == 0) lastTime = currentTime;
// get timer difference and animate
var timePassed:uint = currentTime - lastTime;
lastTime += timePassed;
moveRocks(timePassed);
if (gameMode != "delay") {
moveShip(timePassed);
}
moveMissiles(timePassed);
checkCollisions();
}
From the code you've posted, I can't answer your question safely, but you should check, when startSpaceRocks() is called the first time. This should be in the click handler of your start button.
Beside that, your question title does not reflect the problem. There is no problem with a timer at all, there is a problem, when the "timer" is started.
I've got the following code and i would like to add an delay of 200 ms after each trace statement
for (var x_pos:uint = 0; x_pos <= 12; x_pos++){
for (var y_pos:uint = 0; y_pos <=12; y_pos++){
trace("hello world " +"("x_pos+","+y_pos+")");
//CODE FOR DELAY OF 200ms
}
}
The real situation is a bit more complex but kind of the same:
//For each Row
for (var x_pos:uint = 0; x_pos <= tile_amount-1; x_pos++){
//For each column
for (var y_pos:uint = 0; y_pos <= tile_amount-1; y_pos++){
//New tile;
var newtile:Tile = new Tile;
//Set position
newtile.x = ((40*y_pos)-(40*x_pos));
newtile.y = ((20*y_pos)+(20*x_pos));
//Add to stage
addChild(newtile);
}
}
Anyone any suggestions ?
private var x_pos:uint;
private var y_pos:uint;
private var timer:Timer;
public function startLoop():void
{
x_pos = 0;
y_pos = 0;
timer = new Timer(200);
timer.addEventListener(TimerEvent.TIMER, onTick);
timer.start();
}
private function onTick(event:TimerEvent):void
{
trace("hello world " +"("x_pos+","+y_pos+")");
if (++y_pos <= 12)
return;
y_pos = 0;
if (++x_pos <= 12)
return;
timer.stop();
timer.removeEventListener(TimerEvent.TIMER, onTick);
timer = null;
}
You can't stop the execution of code in the middle of a statement like that, your best bet is to use a timer:
package
{
import flash.events.TimerEvent;
public class Foo
{
private var x_pos:uint = 0;
private var y_pos:uint = 0;
private var timer:Timer;
public function Foo()
{
timer = new Timer(200, 0);
timer.addEventListener(TimerEvent.TIMER, handleTick);
timer.start();
}
public function handleTick(e:TimerEvent):void {
trace("hello world " +"("x_pos+","+y_pos+")");
y_pos++;
if(y_pos > 12){
x_pos++;
y_pos = 0;
}
if(x_pos > 12) timer.stop();
}
}
}
Actionscript does not have a blocking timeout system -- you need to do a recursive function of your own. This following perfect, but it is a start.
import flash.utils.setTimeout;
// call the final function.
delayedRecursion(12,12,200,
function(curX:Number, curY:Number):void
{
trace("hello world " +"("+curX+","+curY+")");
});
//This is really a wrapper around delayedRecursionHelper
function delayedRecursion(maxX:Number, maxY:Number,
delay:Number, callback:Function):void
{
delayedRecursionHelper(0,-1,maxX,maxY,delay,callback);
}
// each time you call this, it creates a function which holds the variables
// passed in, but incremented by 1.
function delayedRecursionHelper(
curX:Number, cury:Number,
maxX:Number, maxY:Number,
delay:Number, called:Function ):Function
{
return function():void
{
called(curX, curY);
// Exit condition: nothing to do here!
if( curX == maxX && curY == maxY ) return;
if( curY == maxY )
{
curY = -1;
curX++;
}
curY++;
setTimeout(delayedRecursionHelper(curX, curY, maxX, maxY, delay), delay);
}
}
You can not delay the loops in as3.
For this purpose you need to use timers. Some help for your solution you can find here: How to show the current progressBar value of process within a loop in flex-as3?
At the end you just need to modify the function logic.