I was working on a test project that I will later incorporate into a much larger work that is a simple quiz game. I made an array with my questions:
var questions1:Array=["nitrogen dioxide","sulfur hexafluoride",..."]
and in a second layer I made a button that cycles through the questions randomly.
import flash.events.MouseEvent;
var qno=0;var rnd1;
function change_question(){
rnd1=Math.ceil(Math.random()*questions1.length)-1;
q.text=questions1[rnd1];
if(questions1[rnd1]=="X"){change_question();}
questions1[rnd1]="X";
}
change_question();
next_b.addEventListener(MouseEvent.CLICK, ButtonAction1);
function ButtonAction1(eventObject:MouseEvent){
qno++;change_question();
}
This part works great, because I was following a tutorial. Text appears in a dynamic text box I created as it should. This tutorial taught to change the value of the array to X with every choice and to ignore choose a different question every time it encountered an X
After it cycles through all the questions I basically get an infinite loop in my output section of flash because it can't find any more non-X values. I was hoping someone had information on how to press a button an change the array back to its default settings so that a teacher (because that is who it is for) has a way of resetting the file when they have reached the end of the quiz.
Thanks everyone!
As per my understanding you wanted to randomize your questions and after showing all the entire questions you wanted to reset your questions.
As per your code you get a random question and updating the same array by pushing value 'X'. Rather than doing this what you need to do is to preserve the array only randomize its position. So that you can use the same value once you cover your all questions
I have added code here.
import flash.events.MouseEvent;
var qno=0;var rnd1;
var questions1:Array=["nitrogen dioxide","sulfur hexafluoride","carbon dioxide","carbon monooxide"];
var nAttmeptedCount = 0;
var shuffledLetters:Array;
function change_question()
{
if(qno == questions1.length)
{
qno = 0;
resetQuestion()
}
else
{
q.text = questions1[shuffledLetters[qno]];
qno++;
}
}
function resetQuestion()
{
shuffledLetters = new Array(questions1.length);
for(var i=0;i<shuffledLetters.length;i++)
{
shuffledLetters[i] = i;
}
shuffledLetters.sort(randomize);
}
function randomize ( a : *, b : * ) : int {
return ( Math.random() > .5 ) ? 1 : -1;
}
resetQuestion()
change_question();
next_b.addEventListener(MouseEvent.CLICK, ButtonAction1);
function ButtonAction1(eventObject:MouseEvent){
change_question();
}
In above solution after showing all questions I have reset the questions automatically. you can modify code as per your requirement. If you want to do the reset questions you can put you code qno = 0;resetQuestion() on button click.
hope above solution work for you.
Related
Last year was my first successful year in teaching my students to create catch and avoid games in Flash with AS3. This year is getting better. Each year I come here for help at least once.
I'm trying to add shooting into the possibilities for their second game project. I can make the shot happen from the ship, gun, whatever, and make it move, and get rid of it when it is off screen, but have not figured out a clean way to have both the shot and the target go away (removeChild and array.splice) upon collision.
The code I have sort of works, but I keep getting the error,
TypeError: Error #1010: A term is undefined and has no properties. at
DropShootV02_fla::MainTimeline/checkShots()
.
Normally I know that this is because of a mismatch between objects and index numbers, but this is related to the call to a second array in removing boxes and bullets.
For simplicity I'll just include the shooting code. Similar organization creates and drops the boxes.
Any help is appreciated. BTW we are not using external script in an AS file.
var shotSpeed = 18;
var shots:Array = new Array();
import flash.events.MouseEvent;
import flash.events.Event;
stage.addEventListener(MouseEvent.CLICK, fireLaser);
function fireLaser(e:MouseEvent):void
{
if (gameOn==true)
{
var shot:Shot=new Shot();
addChild(shot);
shots.push(shot);
shot.gotoAndStop(1);
shot.x = user.x;
shot.y = user.y;
trace(shots.length);
}
}
addEventListener(Event.ENTER_FRAME, moveShot);
function moveShot(e:Event):void
{
for (var i:int=shots.length-1; i>=0; i--)
{
shots[i].y -= shotSpeed;
if (shots[i].y < -25)
{
removeChild(shots[i]);
shots.splice(i,1);
}
}
}
addEventListener(Event.ENTER_FRAME, checkShots);
function checkShots(e:Event):void
{
for (var i:int=shots.length-1; i>=0; i--)
{
for (var k:int=boxes.length-1; k>=0; k--)
{
if (shots[i].hitTestObject(boxes[k]))
{
if (boxes[i].type == "good")
{
score--;
scoreDisplay.text = "Score:" + score;
}
if (boxes[i].type == "bad")
{
score++;
}
removeChild(boxes[k]);
boxes.splice(k,1);
//if I leave this part out I get no errors,
//but but the bullet goes on to strike again
removeChild(shots[i]);
shots.splice(i,1);
}
}
}
}
Thanks kaarto:
I had tried that previously and kept getting the same error. I used that elsewhere in this game code. Turns out I needed to moderate how often the player was shooting. I changed from shooting with the mouse to using space instead and now the problem is gone. Break is definitely a good one here.
Merge move shot and checkShots in one ENTER_FRAME handler.
I have a Volcano class. It's purpose is to randomly spray lavaMass.
In the main class I have made it so that when my character hits the lava, everything is removed, and the deleteLava() function is called.
My problem is that with the deleteLava() function, my Volcano class stops making lava after a few 'deaths'.
Now i gets a little complicated to explain.
I found out that inside the deleteLava() function I should also remove the lavaMass from the array, for it to keep making lava no matter how many 'deaths'.
I used 'lavaSpray.shift();', and tried 'splice'..
And this worked! Except that it doesn't delete all the lavaMass, so everytime the character dies a few of the lavaMass objects keeps hanging around in the level, not moving. So after many 'deaths' there is a lot of lavaMass objects just standing still, not moving and not being deleted.
Here's the volcano class:
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Volcano extends MovieClip {
var lavaSpray:Array = [];
var lavaNum:Number;
var world:World;
public function LavaThing() {
addEventListener(Event.ENTER_FRAME, makeLava)
}
public function deleteLava()
{
this.parent.removeChild(this)
for (var m = 0; m < lavaSpray.length; m++) {
if (lavaSpray[m].parent) {
lavaSpray[m].parent.removeChild(lavaSpray[m]);
}
}
}
function makeLava (e:Event)
{
lavaNum = Math.random()*70
if (lavaSpray.length<20)
{
if (lavaNum > 68.15)
{
var lavaMass = new LavaMass();
lavaSpray.push(lavaMass);
addChild(lavaMass);
lavaMass.scaleY = 0.5;
lavaMass.scaleX = 0.5;
lavaMass.x += 90;
lavaMass.y += Math.random()*30
lavaMass.y -= Math.random()*30
}
}
for each (lavaMass in lavaSpray)
{
lavaMass.x += 4;
if (lavaMass.parent && lavaMass.x > 800)
{
lavaMass.parent.removeChild(lavaMass);
lavaSpray.shift();
}
}
}
}
}
I hope someone knows what I'm talking about. Thanks in advance.
I put up a video with my problem:
https://www.youtube.com/watch?v=rYxYHB7rcgY&feature=youtu.be
I suspect the issues is:
you don't remove the ENTER_FRAME Event Listener when you delete the lava.
removing the child doesn't mean you deleted it's listener.
so you may remove all the lava , but still the ENTER_FRAME creates more !
you have to remove it your self.
so you have to add
removeEventListener(Event.ENTER_FRAME, makeLava)
as the first line at your function deleteLava()
....
or you may add
addEventListener(Event.REMOVED_FROM_STAGE, onRemoved)
and create onRemoved(e:Event){} function
then inside this function remove any listener you Added , including the ENTER_FRAME & the REMOVED_FROM_STAGE
try to read more about these subjects
Game Loop
entity system framework
Pool Object pattern
I may but links , but I prefer you Google them , and read from different resources - whatever the language they are explained with -
good luck
just for clarrifying your question.. You added the lavamass inside the volacano class? and you need to remove lavamass or volcano ? Dp you get any error during compilation? Also i encountered some thing like this when developing a shooting game, the removed bullets shows up after removing the bullerts. What i did was , i just added the bullets into a empty movieclip and removed the entire clip.
So I'm real new to AS3 and I'm trying to figure out a solution to end a function I created for a matching game. I want to have the function end when all the cards are used up in the array. What is the easiest way to go about this?
private var games:Object = {
easy:{
tiledeck:[1,1,2,2]
,xOffset:450
,yOffset:320
,incrementX:200
,incrementY:200
,columns:2
,rows:2
}
,hard:{
tiledeck:[1,1,2,2,3,3,4,4]
,xOffset:235
,yOffset:320
,incrementX:200
,incrementY:200
,columns:4
,rows:2
}
};
public function KT(game:String){
buttonMode = true
var gameConfig = games[game];
var tiledeck:Array = gameConfig.tiledeck.concat();
for (var x=1; x<=gameConfig.columns; x++){
for (var y=1; y<=gameConfig.rows; y++){
var random_card = Math.floor(Math.random() * tiledeck.length);
var tile:animalTile = new animalTile();
tile.animal = tiledeck[random_card];
tiledeck.splice(random_card,1);
tile.gotoAndStop(5);
tile.x = (x - 1) * gameConfig.incrementX + gameConfig.xOffset;
tile.y = (y - 1) * gameConfig.incrementY + gameConfig.yOffset;
tile.addEventListener(MouseEvent.CLICK,tile_clicked);
addChild(tile);
}
}
}
Your problem is not what you think it is.
The array is properly discarded from memory.
However, you used addChild(tile). This means you'll also have to removeChild(tile). Personally, I recommend adding a DisplayObjectContainer that you add the cards to. Kinda like a plastic sheet to put the cards on. Then, when the user presses the back button, you remove the plastic sheet... and all the cards come with it.
You haven't provided the code for the back button though, so I can't help you with integrating this functionality. My advice: Make some sort of game object responsible for cleanup, so all the button has to do is game.exitGame(); and then whatever code you use to go back right now.
So I'm facing a problem with an AS3 class that's not operating the way I need it to. It's a simple problem, but a complex set of methods that cause it.
Firstly, the 'quiz' I'm building has 6 questions loaded as external SWFs inside of a Shell, run by a class. First we declared a var "a_quiz" to hold 6 values pushed from the external SWFs. These 6 values are reduced to a string and then checked against another array that contains the correct answers. The following loadQuiz function is designed to launch one of three random quizes and clear the a_quiz array so it can take new answers:
public function loadQuiz():void {
a_quiz.length=0;
trace("loadQuiz");
n_quizCorrect = n_quizScore = 0;
n_currentQuiz = Math.floor(Math.random() * (n_totalTopics - n_quizStart + 1) + n_quizStart);
loadTopic(n_currentQuiz);
}
Now I've tested the Shell and confirmed that the trace "loadQuiz" fires every time. And the first time you load the quiz, everything behaves as it should. The 6 questions trace correct or incorrect responses and push 6 binary values into the a_quiz array. The output looks like this:
loadQuiz
incorrect
correct
incorrect
incorrect
incorrect
incorrect
0,1,0,0,0,0
you failed
Then I jump back to the main menu and launch again. This deploys the loadQuiz function all over again. The first line of the function:
a_quiz.length=0;
should be emptying the a_quiz array to accept new answers to mark against. But when I complete the quiz I get this:
loadQuiz
correct
correct
correct
correct
correct
correct
,,,,,,1,1,1,1,1,1
you failed
For some reason beyond my understanding, the push values are stacking on top of empty positions, so when the strings compare...they won't match. What is going on here?
The push function:
function handleClick(evt:MouseEvent):void{
var tempCORRECT = a_answerSheet.toString();
var tempSELECTION = a_selected.toString();
//
if(tempSELECTION == tempCORRECT){
trace('correct');
parentObj1.a_quiz[ parentObj1.n_currentQuestion - 1 ] = 1;
}else{
trace('incorrect');
parentObj1.a_quiz[ parentObj1.n_currentQuestion - 1 ] = 0;
}
parentObj1.n_currentQuestion ++;
// GOTO NEXT SLIDE
parentObj1.LOADNEXT('up');
}
The problem originated in the loading of the Quiz itself.
as you can see on the handleClick function:
parentObj.n_currentQuestion++
was increasing an integer variable on the parentObj's timeline called n_currentQuestion. The problem then, originated in how the quiz was logging n_currentQuestion when the quiz loads with this function:
public function loadQuiz():void {
a_quiz= [];
trace("loadQuiz");
n_quizCorrect = n_quizScore = 0;
n_currentQuiz = Math.floor(Math.random() * (n_totalTopics - n_quizStart + 1) + n_quizStart);
loadTopic(n_currentQuiz);
}
So to correct the error, I needed to add a line to the loadQuiz, so that it would always load with n_currentQuestion set to 1.
public function loadQuiz():void {
a_quiz= [];
n_currentQuestion = 1;
trace("loadQuiz");
n_quizCorrect = n_quizScore = 0;
n_currentQuiz = Math.floor(Math.random() * (n_totalTopics - n_quizStart + 1) + n_quizStart);
loadTopic(n_currentQuiz);
}
I have a few different question and i have decided to put them in one. So the first question : If i have one and the same code(for example):
buttonsA.buton1a.addEventListener(MouseEvent.MOUSE_DOWN , buton1a_function);
buttonsA.buton2a.addEventListener(MouseEvent.MOUSE_DOWN , buton2a_function);
buttonsA.buton3a.addEventListener(MouseEvent.MOUSE_DOWN , buton3a_function);
buttonsA.buton4a.addEventListener(MouseEvent.MOUSE_DOWN , buton4a_function);
buttonsA.buton5a.addEventListener(MouseEvent.MOUSE_DOWN , buton5a_function);
buttonsA.buton6a.addEventListener(MouseEvent.MOUSE_DOWN , buton6a_function);
buttonsA.buton7a.addEventListener(MouseEvent.MOUSE_DOWN , buton7a_function);
buttonsA.buton8a.addEventListener(MouseEvent.MOUSE_DOWN , buton8a_function);
buttonsA.buton9a.addEventListener(MouseEvent.MOUSE_DOWN , buton9a_function);
buttonsA.buton10a.addEventListener(MouseEvent.MOUSE_DOWN , buton10a_function);
and i want to put it in several places(in different conditions) can i put them in a function a call a function instead a copying a large amout of text (I thought about 'include' from a different file but i want to keep all the information in one file).
The second question is about arrays : In my situation i have an array and i .push() a different numbers in it.But it could be "1,51,11,2,13' or "1,2,3,4,5" so every time place of numbers (and numbers themselves) are different. How can i say to AS3 in function to remove(.splice) exactly the number 5 or 6 (in spite of their place in the array).
The third question is again about the "code" that is upper in the question. Can i maybe with the loop for to make all these 10 addEventListen with a fewer code (i think it should be something like that:)
for(var i:int = 1; i <= 100; i++){
//buttonsA.buton'i'a.addEventListener(MouseEvent.MOUSE_DOWN , buton'i'a_function);
}
Long story short maybe i didn't have to put so much question and maybe my thoughts are not correct, but i think that my questions are easy but i can't solve them. Any decisions and replies are welcomed :) Thanks.
First Question:
Not sure I understand your first question. I'll take a stab at it and say you're wanting the functionality of the button mouse down to be enabled during different contexts of your application state, but you don't want to repeat all the event listeners all the time?
if so, you should make a subclass for all your button to inherit from. It could look something like this:
public class ButtonSubClass extends Sprite { //or simple button, or whatever
public function ButtonSubClass():void {
this.addEventListener(MouseEvent.MOUSE_DOWN,downHandler,false,0,true);
}
private function downHandler(e:MouseEvent):void {
//do something common to all your buttons here
}
}
Then, have all your buttons inherit from this class.
Second Question:
function removeFromArray(elementVal:*):void {
var index:int = array.indexOf(elementVal); //get the index of the first element whose value is the passed parameter;
if(index >= 0){
array.splice(index,1); //remove that element/index from the array.
}
}
Third Question:
If ButtonA is a sprite whose only children are all the buttons you want the listener for, then you can do this:
var i:int = buttonA.numChildren;
while(i--){
buttonsA.getChildAt(i).addEventListener(MouseEvent.MOUSE_DOWN , button_function);
}
function button_function(e:Event):void {
switch(e.currentTarget){
case button1a:
//do something with button 1a
break;
case button2a
//do something with button 2a
break;
}
}
OR, more sloppily and less efficient and not recommended, this:
for(var i:int=1;i<=10;i++){
this["buton" + i.toString() + "a"].addEventListener(MouseEvent.MOUSE_DOWN, this["buton" + i.toString() + "a_function"]);
}