ActionScript Quiz

umhr_quizeActionScriptのクイズを作った。先日のProgression版を元にして、作り直し。
制限時間がポイントになるようにした。クイズのデータはGoogleDocsのスプレッドシートから読むので更新が簡単。

Get Adobe Flash player

Progressionに感化されて、画面遷移用のPageクラスを作って管理している。

▼Wonderfl
http://wonderfl.net/code/9eef2eb033b6c57fa8db141bb74f68134e107c40

▼ActionScript AS3(FP9)
[sourcecode language=”as3″]
/*
* ActionScript Quiz
*
* 問題登録はここから
* https://spreadsheets.google.com/viewform?hl=ja&formkey=dGlIREVzc2JCMVk4NHlZajlmdnpiQkE6MA
* 設問はコチラ
* https://spreadsheets.google.com/ccc?key=0Akpu7nsnVtwIdGlIREVzc2JCMVk4NHlZajlmdnpiQkE&hl=ja
*
* GoogleDocumentのフォームの結果を表示
* http://wonderfl.net/code/135bbc7fb447b0ed49dc90d5b92a57b52bdd6e72
* */

package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.net.URLLoader;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.events.MouseEvent;

import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.tweens.ITween;
import org.libspark.betweenas3.events.TweenEvent;

/**
* …
* @author umhr
*/
[SWF(width="465", height="465", frameRate="30", backgroundColor="0x888888")]
public class Main extends Sprite
{
private var question_array:Array;
private var _pages:Array;
public function Main():void {
var myURLLoader:URLLoader = new URLLoader();
myURLLoader.addEventListener (Event.COMPLETE, onCompleteXML);
//YahooPipesの汎用feedProxy
var xmlURL:String = "http://pipes.yahooapis.com/pipes/pipe.run?_id=f4f6c98189a88373b9bfd4fe6128c018&_render=rss&url=";
//encodeURIComponentでエスケープして、feedProxyにくっつける。
xmlURL += encodeURIComponent("http://spreadsheets.google.com/feeds/cells/tiHDEssbB1Y84yYj9fvzbBA/od6/public/basic?alt=rss&rand="+Math.random());
myURLLoader.load(new URLRequest(xmlURL));
}

private function onCompleteXML(e:Event):void {
var myXML:XML = new XML(e.currentTarget.data);
question_array = [];
//var count:int;
for (var i:int = 0; i < myXML.channel.item.length(); i++) {
var lineNum:Number = Number(String(myXML.channel.item[i].title).substr(1))-1;
var columnNum:Number = String(myXML.channel.item[i].title).substr(0,1).charCodeAt() – 65;
if(lineNum > 0){
var str:String = String(myXML.channel.item[i].description);
str = str.replace(/&gt;/g,">");
str = str.replace(/&lt;/g,"<");
str = str.replace(/&nbsp;/g," ");
str = str.replace(/&amp;/g,"&");
str = str.replace(/&#92;n/g,"\n");
if(columnNum == 0){
question_array[lineNum-1] = {name:"",q:[]};
}else if(columnNum == 1){
//trace("title",str);
question_array[lineNum-1]["title"] = str;
}else if(columnNum <= 6){
//trace("q",str);
if(str.length > 0){
question_array[lineNum-1]["q"].push(str);
}
}else if(columnNum == 7){
if(str == ""){
question_array[lineNum-1]["a"] = [0];
}else{
question_array[lineNum-1]["a"] = str.split(",");
}
//trace(question_array[lineNum-1]["a"])
}
}
}

atConstract();
}
public function atConstract():void{
var dataUnit:Object = {"question_array":question_array,score:0,timeScore:0,order:[]};

_pages = [new StartPage({page:1, "dataUnit":dataUnit}),
new QPage({page:2,qNumber:0, "dataUnit":dataUnit}),new QPage({page:3,qNumber:1, "dataUnit":dataUnit}),
new QPage({page:4,qNumber:2, "dataUnit":dataUnit}),new QPage({page:5,qNumber:3, "dataUnit":dataUnit}),
new QPage({page:6,qNumber:4, "dataUnit":dataUnit}),new QPage({page:7,qNumber:5, "dataUnit":dataUnit}),
new QPage({page:8,qNumber:6, "dataUnit":dataUnit}),new QPage({page:9,qNumber:7, "dataUnit":dataUnit}),
new QPage({page:10,qNumber:8, "dataUnit":dataUnit}),new QPage({page:11,qNumber:9, "dataUnit":dataUnit}),
new EndPage({page:12, "dataUnit":dataUnit,"length":question_array.length})];
for (var i:int = 0; i < _pages.length; i++) {
_pages[i].onClose = pageSorter;
this.addChild(_pages[i]);
}
var score:TextField = Create.newTextField({defaultTextFormat:new TextFormat("_sans",14)},{text:"TimeScore:0",width:200,height:20,x:20,y:20})
this.addChild(score)

_pages[0].open = true;

function pageSorter(localData:Object):void {
dataUnit.timeScore = Math.round(dataUnit.timeScore*10)/10;
score.text = "TimeScore:"+dataUnit.timeScore;
_pages[localData.page%_pages.length].open = true;
}

}
}
}

import flash.display.Sprite;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.MouseEvent;
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.tweens.ITween;
class Page extends Sprite {
private var _open:Boolean;
protected var _localData:Object;
public var onOpen:Function = function(obj:Object = null):void { };
public var onClose:Function = function(obj:Object = null):void { };
public function Page(obj:Object = null) {
_localData = obj;
atConstract();
}

protected function atConstract():void {
this.graphics.beginFill(0xFF0000, 0.5);
this.graphics.drawRect(0, 0, 100, 100);
this.graphics.endFill();
this.visible = false;
this.addEventListener(MouseEvent.CLICK , function(e:MouseEvent):void{e.target.open = false});
}

/**
* このページを開きはじめた瞬間に送出されます。
*/
protected function atOpen():void {
this.visible = true;
var t:ITween;
t = BetweenAS3.serial(
BetweenAS3.tween(this, { y: 0,alpha:1 }, { y:30,alpha:0 }, 0.3),
BetweenAS3.func(onOpen,[_localData])
)
t.play();
}

/**
* このページを閉じはじめた瞬間に送出されます。
*/
protected function atClose():void {
var t:ITween;
t = BetweenAS3.serial(
BetweenAS3.tween(this, { y: -30,alpha:0 }, { y:0,alpha:1 }, 0.2),
BetweenAS3.func(function():void { visible = false } ),
BetweenAS3.func(onClose,[_localData])
)
t.play();
}

public function set open(boolean:Boolean):void {
if (this._open == boolean) { return };
if (boolean) {
atOpen();
}else {
atClose();
}
this._open = boolean;
}

public function get open():Boolean { return this._open };
}

class QPage extends Page {
private var _counter:TextField;
private var _kekka:Sprite;
public function QPage(obj:Object){
super(obj);
}
override protected function atConstract():void {
this.graphics.beginFill(0xCC6666, 1);
this.graphics.drawRect(8, 8, 465-16, 465-16);
this.graphics.endFill();
this.visible = false;
_kekka = new Sprite();
this.addChild(_kekka);
}
override protected function atOpen():void {
super.atOpen();
while (this.numChildren > 0) {
this.removeChildAt(0);
}
//第何問目か
var order:int = _localData.dataUnit.order[_localData.qNumber];
//設問文
var titleStr:String = _localData.dataUnit.question_array[order].title;
this.addChild(Create.newTextField({defaultTextFormat:new TextFormat("_sans",14),autoSize:"center",x:465/2,y:140},{htmlText:titleStr}));
//選択肢をシャッフルして並べる
var shuffle_ar:Array = shuffle(_localData.dataUnit.question_array[order].q.length);
for (var i:int = 0; i < _localData.dataUnit.question_array[order].q.length; i++) {
var j:int = shuffle_ar[i];
var btn:SimpleButton = Create.newSimpleButton({text:_localData.dataUnit.question_array[order].q[j]});
btn.name = String(kotaeawase(j,_localData.dataUnit.question_array[order].a)?1:0);
btn.x = (465-btn.width)/2;
btn.y = 180+i*40;
this.addChild(btn);
}
addCounter();
this.removeEventListener(MouseEvent.CLICK,toClose);
this.addEventListener(MouseEvent.CLICK,toClose);
}
private var _timer:Timer;
private function addCounter():void{
_counter = Create.newTextField({defaultTextFormat:new TextFormat("_sans",14)},{width:200,x:20,y:40,selectable:false})
_timer = new Timer(100,120);
_timer.addEventListener(TimerEvent.TIMER_COMPLETE,onTimerComplete);
_timer.addEventListener(TimerEvent.TIMER,onTimer);
_timer.start();
this.addChild(_counter);
}
private function onTimer(e:TimerEvent):void{
_counter.text = "Q:"+String(_localData.qNumber+101).substr(1,2)+", Time:"+String(Math.min(100,120-e.target.currentCount)/10);
}
private function onTimerComplete(e:TimerEvent):void{
this.open = false;
}
private var _answer:int;
override protected function atClose():void {
_timer.removeEventListener(TimerEvent.TIMER_COMPLETE,onTimerComplete);
_timer.removeEventListener(TimerEvent.TIMER,onTimer);
_kekka.graphics.clear();
if (_answer) {
_kekka.graphics.lineStyle(24, 0xFF0000);
_kekka.graphics.drawCircle(465 / 2, 465 / 2, 100);
}else {
_kekka.graphics.lineStyle(24, 0xFF);
_kekka.graphics.moveTo(165, 165);
_kekka.graphics.lineTo(300, 300);
_kekka.graphics.endFill();
_kekka.graphics.moveTo(165, 300);
_kekka.graphics.lineTo(300, 165);
_kekka.graphics.endFill();
}

this.addChild(_kekka);

var t:ITween;
t = BetweenAS3.serial(

BetweenAS3.tween(_kekka, { alpha:0 }, { alpha:1 }, 0.2),
BetweenAS3.tween(this, { y: -30,alpha:0 }, { y:0,alpha:1 }, 0.2),
BetweenAS3.func(function():void { visible = false } ),
BetweenAS3.func(onClose,[_localData])
)
t.play();
//super.atClose();
}
private function kotaeawase(num:int,ar:Array):Boolean{
var boolean:Boolean;
for (var i:int = 0; i < ar.length; i++) {
if(num == ar[i]){
boolean = true;
break;
}
}
return boolean;
}
private function shuffle(num:int):Array {
var _array:Array = new Array();
for (var i:int= 0; i<num; i++){
_array[i] = Math.random();
}
return _array.sort(Array.RETURNINDEXEDARRAY);
}

private function toClose(e:MouseEvent):void{
if(e.target.name.length < 2){
this.removeEventListener(MouseEvent.CLICK,toClose);
_answer = Number(e.target.name);
_localData.dataUnit.timeScore += _answer*Number((_counter.text).substr(11));
_localData.dataUnit.score += _answer;
this.open = false;
//trace(e.target.name,_localData.dataUnit.score)
}
}
}
class StartPage extends Page {
public function StartPage(obj:Object){
super(obj);
}
override protected function atConstract():void {
this.graphics.beginFill(0xEEEEEE, 1);
this.graphics.drawRect(8, 8, 465-16, 465-16);
this.graphics.endFill();
this.visible = false;
var titleStr:String = "やあみんな、ActionScript Quizの時間だよ!\n何問正解できるかな?";
this.addChild(Create.newTextField({defaultTextFormat:new TextFormat("_sans",14)},{x:100,y:180},{text:titleStr,autoSize:"left"}));
var btn:SimpleButton = Create.newSimpleButton({text:"開始 !"});
btn.x = (465-btn.width)/2;
btn.y = 280;
btn.addEventListener(MouseEvent.CLICK,toClose);
this.addChild(btn);
}
override protected function atOpen():void {
//質問の順番をシャッフルするために
_localData.dataUnit.order = shuffle(_localData.dataUnit.question_array.length);
// _localData.dataUnit.timeScore = 0;
// _localData.dataUnit.score = 0;
super.atOpen();
}
private function shuffle(num:int):Array {
var _array:Array = new Array();
for (var i:int= 0; i<num; i++){
_array[i] = Math.random();
}
return _array.sort(Array.RETURNINDEXEDARRAY);
}
private function toClose(e:MouseEvent):void{
this.open = false;
}
}

class EndPage extends Page {
public function EndPage(obj:Object){
super(obj);
}
override protected function atConstract():void {
this.graphics.beginFill(0x333333, 1);
this.graphics.drawRect(8, 8, 465-16, 465-16);
this.graphics.endFill();
this.visible = false;
}
override protected function atOpen():void {
while (this.numChildren > 0) {
this.removeChildAt(0);
}
var titleStr:String = "お疲れ様でした。\n"
titleStr += "あなたは10問中 " + _localData.dataUnit.score + " 問正解 、\n";
titleStr += "得点は " + _localData.dataUnit.timeScore + " 点でした。\n\n";
titleStr += "現在このQuizには "+_localData.length+" 問 登録されています。\n";
titleStr += "もう一回やる?";
this.addChild(Create.newTextField({defaultTextFormat:new TextFormat("_sans",14)},{text:titleStr,autoSize:"left",x:100,y:140,textColor:0xFFFFFF}));
var btn:SimpleButton = Create.newSimpleButton({text:"やる !"});
btn.x = (465-btn.width)/2;
btn.y = 280;
btn.addEventListener(MouseEvent.CLICK,toClose);
this.addChild(btn);
super.atOpen();
}
private function shuffle(num:int):Array {
var _array:Array = new Array();
for (var i:int= 0; i<num; i++){
_array[i] = Math.random();
}
return _array.sort(Array.RETURNINDEXEDARRAY);
}
private function toClose(e:MouseEvent):void{
this.open = false;
_localData.dataUnit.timeScore = 0;
_localData.dataUnit.score = 0;
}
}

//////////////////////////////////////////////////////////////////
import flash.display.DisplayObject;
import flash.display.Graphics;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.display.Sprite;
import flash.display.Shape;
import flash.display.SimpleButton;
import flash.display.BitmapData;
import flash.display.Bitmap;

class Create{
public static var defaultTextFormat:TextFormat = new TextFormat();

public static function newSimpleButton(… args):SimpleButton {

var propObj:Object = { x:0, y:0, width:0, height:0, color:0xFF0000, alpha:1, round:0, lineSize:0, lineColor:0, lineAlpha:1, ellipseWidth:0, ellipseHeight:0, text:"" };

if(args){
for (var i:int = 0; i < args.length; i++) {
for (var str:String in args[i]) {
propObj[str] = args[i][str];
}
}
}

if (propObj.text) {
var tf:TextField = newTextField( { y:2, text:propObj.text, setTextFormat:[ { font:"_sans", align:"center" } ], autoSize:"center" } );
}

if (!(propObj.width)) {
propObj.width = tf.width + 16;
}
if (!(propObj.height)) {
propObj.height = tf.height + 4;
}

var upState:Sprite = newSprite( { x:propObj.x, y:propObj.y }, drawRect( { color:0xCCCCCC, width:propObj.width, height:propObj.height, round:8 } ) );
upState.addChild(newShape( { x:2, y:2 }, drawRect( { color:0xE5E5E5, width:propObj.width – 4, height:propObj.height – 4, round:6 } )));
var overState:Sprite = newSprite( { x:propObj.x, y:propObj.y }, drawRect( { color:0xBBBBBB, width:propObj.width, height:propObj.height, round:8 } ));
overState.addChild(newShape( { x:2, y:2 }, drawRect( { color:0xEEEEEE, width:propObj.width – 4, height:propObj.height – 4, round:6 } )));
var downState:Sprite = newSprite( { x:propObj.x, y:propObj.y }, drawRect( { color:0xAAAAAA, width:propObj.width, height:propObj.height, round:8 } ));
downState.addChild(newShape( { x:2, y:2 }, drawRect( { color:0xDDDDDD, width:propObj.width – 4, height:propObj.height – 4, round:6 } )));
var hitTestState:Shape = newShape( { x:propObj.x, y:propObj.y }, drawRect( { width:propObj.width, height:propObj.height, round:8 } ));
if (propObj.text) {
upState.addChild(newTextField({y:2,width:propObj.width,height:propObj.height-2,text:propObj.text,setTextFormat:[{font:"_sans",align:"center"}]}));
overState.addChild(newTextField({y:2,width:propObj.width,height:propObj.height-2,text:propObj.text,setTextFormat:[{font:"_sans",align:"center"}]}));
downState.addChild(newTextField({y:3,width:propObj.width,height:propObj.height-3,text:propObj.text,setTextFormat:[{font:"_sans",align:"center"}]}));
}
var sb:SimpleButton = new SimpleButton(upState, overState, downState, hitTestState);

return sb;
}

public static function drawRect(… args):Object {
var propObj:Object = { x:0, y:0, width:100, height:100, color:0xFF0000, alpha:1, round:0, lineSize:0, lineColor:0, lineAlpha:1, ellipseWidth:0, ellipseHeight:0 };

if(args){
for (var i:int = 0; i < args.length; i++) {
for (var str:String in args[i]) {
propObj[str] = args[i][str];
}
}
}
if(!(propObj.ellipseWidth)){
propObj.ellipseWidth = propObj.round;
}
if(!(propObj.ellipseHeight)){
propObj.ellipseHeight = propObj.ellipseWidth;
}

var resultArray:Array = [];
resultArray.push({ beginFill:[propObj.color, propObj.alpha] });
if (propObj.lineSize > 0) {
resultArray.push( { lineStyle:[propObj.lineSize, propObj.lineColor, propObj.lineAlpha] } );
}
if(propObj.round || propObj.ellipseWidth || propObj.ellipseHeight){
resultArray.push( { drawRoundRect:[propObj.x, propObj.y, propObj.width, propObj.height, propObj.ellipseWidth, propObj.ellipseHeight] } );
}else {
resultArray.push( { drawRect:[propObj.x, propObj.y, propObj.width, propObj.height] } );
}
return { graphics:resultArray };
}
public static function drawCircle(… args):Object {
var propObj:Object = { x:0, y:0, width:0, height:0, color:0xFF0000, alpha:1, r:100, radius:0, lineSize:0, lineColor:0, lineAlpha:1 };

if(args){
for (var i:int = 0; i < args.length; i++) {
for (var str:String in args[i]) {
propObj[str] = args[i][str];
}
}
}
if(!(propObj.radius)){
propObj.radius = propObj.r;
}
if(!(propObj.width)){
propObj.width = propObj.radius;
}
if(!(propObj.height)){
propObj.height = propObj.radius;
}

var resultArray:Array = [];
resultArray.push({ beginFill:[propObj.color, propObj.alpha] });
if (propObj.lineSize > 0) {
resultArray.push( { lineStyle:[propObj.lineSize, propObj.lineColor, propObj.lineAlpha] } );
}
if (propObj.width == propObj.height) {
resultArray.push( { drawCircle:[propObj.x, propObj.y, propObj.radius] } );
}else {
resultArray.push( { drawEllipse:[propObj.x, propObj.y, propObj.width, propObj.height] } );
}

return { graphics:resultArray };
}

public static function newShape(… args):Shape {
var sp:Shape;
var str:String;
var length:int = args.length;
for (var i:int = 0; i < length; i++) {
var obj:Object = args[i];
if(i == 0){
if(obj.Shape){
sp = obj.Shape;
}else{
sp = new Shape();
}
}
if(obj.graphics){
for (var j:int = 0; j < obj.graphics.length; j++) {
if(obj.graphics[j]){
for (str in obj.graphics[j]) {
sp.graphics[str].apply(null, obj.graphics[j][str]);
}
}
}
}
for (str in obj) {
if(str != "Shape" && str != "graphics"){
sp[str] = obj[str];
}
}
}
return sp;
}
public static function newSprite(… args):Sprite {
var sp:Sprite;
var str:String;
var length:int = args.length;
for (var i:int = 0; i < length; i++) {
var obj:Object = args[i];
if(i == 0){
if(obj.Sprite){
sp = obj.Sprite;
}else{
sp = new Sprite();
}
}
if(obj.graphics){
for (var j:int = 0; j < obj.graphics.length; j++) {
if(obj.graphics[j]){
for (str in obj.graphics[j]) {
sp.graphics[str].apply(null, obj.graphics[j][str]);
}
}
}
}
for (str in obj) {
if(str != "Sprite" && str != "graphics" && str != "addChild"){
sp[str] = obj[str];
}
}
if(obj.addChild){
sp.addChild(obj.addChild);
}
}
return sp;
}
public static function newTextField(… args):TextField {
var ta:TextField = new TextField();
ta.defaultTextFormat = defaultTextFormat;
var length:int = args.length;
for (var i:int = 0; i < length; i++) {
var obj:Object = args[i];
for (var str:String in obj) {
if(str != "setTextFormat"){
ta[str] = obj[str];
}
}
if(obj.setTextFormat){
var format:TextFormat = new TextFormat();
if(obj.setTextFormat[0] is TextFormat){
format = obj.setTextFormat[0];
}else{
for (var tfstr:String in obj.setTextFormat[0]) {
format[tfstr] = obj.setTextFormat[0][tfstr];
}
}
ta.setTextFormat(format,isNaN(obj.setTextFormat[1])?-1:obj.setTextFormat[1],isNaN(obj.setTextFormat[2])?-1:obj.setTextFormat[2]);
}
}
return ta;
}

public static function newBitmap(… args):Bitmap {
var length:int = args.length;
var bd:BitmapData;
var bitmap:Bitmap;
var strObj:Object = { width:100 , height:100, transparent:true, fillColor:0xFFFFFFFF , pixelSnapping:"auto", smoothing:false ,x:0 ,y:0};

var tempDO:DisplayObject;
for (var i:int = 0; i < length; i++) {
var obj:Object = args[i];
for (var str:String in obj) {
if (str == "draw") {
tempDO = obj[str];
strObj.width = obj[str].width;
strObj.height = obj[str].height;
}else {
strObj[str] = obj[str];
}
}
}
bd = new BitmapData(strObj.width, strObj.height, strObj.transparent, strObj.fillColor);

if (tempDO) {
bd.draw(tempDO)
}
bitmap = new Bitmap(bd, strObj.pixelSnapping, strObj.smoothing);
bitmap.x = strObj.x;
bitmap.y = strObj.y;
return bitmap;
}
}
[/sourcecode]