topical media & game development
#Player.mx
#Player.mx
[swf]
flex
<?xml version="1.0" encoding="utf-8"?>
<mx:Box xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="xinit()" horizontalGap="0" verticalGap="0"
creationComplete="finalize()"
paddingBottom="0" paddingLeft="0" paddingRight="0" paddingTop="0">
<mx:Metadata>
/*
* Dispatched when the playlist reaches the end.
*
* @eventType net.ximpel.events.InteractiveMediaEvent.COMPLETE
*/
[Event(name="complete", type="net.ximpel.events.InteractiveMediaEvent")]
/*
* Dispatched when the next item in the playlist is played.
*
* @eventType net.ximpel.events.InteractiveMediaEvent.NEXT_ITEM
*/
[Event(name="nextItem", type="net.ximpel.events.InteractiveMediaEvent")]
/*
* Dispatched when the current item in the playlist is paused.
*
* @eventType net.ximpel.events.InteractiveMediaEvent.PAUSE
*/
[Event(name="pause", type="net.ximpel.events.InteractiveMediaEvent")]
/*
* Dispatched when the previous item in the playlist is played.
*
* @eventType net.ximpel.events.InteractiveMediaEvent.PREVIOUS_ITEM
*/
[Event(name="previousItem", type="net.ximpel.events.InteractiveMediaEvent")]
/*
* Dispatched when the current item in the playlist is unpaused.
*
* @eventType net.ximpel.events.InteractiveMediaEvent.RESUME
*/
[Event(name="resume", type="net.ximpel.events.InteractiveMediaEvent")]
/*
* Dispatched when the score changes.
*
* @eventType net.ximpel.events.ScoreEvent.SCORE_CHANGED
*/
[Event(name="scoreChange", type="net.ximpel.events.ScoreEvent")]
/*
* Dispatched when the subject changes.
*
* @eventType net.ximpel.events.SubjectEvent.SUBJECT_CHANGED
*/
[Event(name="subjectChange", type="net.ximpel.events.SubjectEvent")]
</mx:Metadata>
<!--All urls, paths etc. are read from a config file-->
<mx:HTTPService
id="configService"
resultFormat="e4x"
result="configServiceResultHandler(event)"
fault='{Alert.show("Cannot load file " + configService.url)};'
/>
<mx:HTTPService
id="ximpelService"
url=""
resultFormat="e4x"
result="ximpelServiceResultHandler(event)"
fault='{Alert.show("Cannot load xml file: "+ ximpelService.url)};'
/>
<mx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;
import mx.controls.Alert;
import mx.events.*;
import net.ximpel.events.*;
import net.ximpel.iv.*;
import net.ximpel.score.ScoreThreshold;
import flash.filters.*;
import flash.net.LocalConnection;
import flash.display.StageDisplayState;
import mx.managers.SystemManager;
import flash.events.ContextMenuEvent;
public static const VERSION:String = "XIMPEL v1.5";
public static const MINIGAME_MEDIA:String = "minigameMedia";
public static const VIDEO_MEDIA:String = "videoMedia";
public var trace : Function;
[Bindable]
public var EXTRA_QUESTION_RIGHT_LABEL:String = "Right!";
[Bindable]
public var EXTRA_QUESTION_WRONG_LABEL:String = "Wrong!";
[Bindable]
public var EXTRA_SEGMENT_LABEL:String = "Extra footage!";
[Bindable]
public var QUESTION_LABEL:String = "Question";
private var _incoming_lc:LocalConnection;
private var _configFile:XML;
private var _videoFeed:XML;
private var _videoDir:String = "";
private var _assetsDir:String = "";
private var _currentSubject:int;
private var _currentVideo:int;
private var _subjectNameTraceArray:Array;
private var _subjectLongnameTraceArray:Array;
private var _videoFileTraceArray:Array;
private var _overlayArray:Array;
private var _gameScore:Number;
private var _extraQuestionAnswer:Boolean;
private var _extraQuestionTimer:Timer;
private var _extraQuestionEvaluationTimer:Timer;
private var _loadVideoPlayListFromConfig:Boolean;
private var _gameScoreArray:Array;
private var _bonusScoreArray:Array;
private var _randomVideoArray:Array;
private var _gameScoreMessageArray:Array;
private var _currentMediaType:String;
private var _clickOverlaySubjectName:Array;
private var _overlayCelArray:Array;
private var _extraQuestionArray:Array;
private var SCORE_MULTIPLIER:Number = 1000;
private var EXTRA_QUESTION_TIME:int = 6;
private const EXTRA_QUESTION_SCORE:Number = 0.5;
private const FLASH_VIDEO_EXTENSION:String = ".flv";
private const MP4_VIDEO_EXTENSION:String = ".mp4";
private const MINIGAME_EXTENSION:String = ".swf";
private const EXTRA_QUESTION_EVALUATION_TIME:int = 2;
private const ERROR_MESSAGE_TIME:int = 2;
private const DEFAULT_OVERLAY_ALPHA:Number = 0.3;
private const DEFAULT_OVERLAY_HOVER_ALPHA:Number = 0.6;
private const DEFAULT_OVERLAY_COLOR:String = "0xffc0c0";
private const DEFAULT_EXTRA_QUESTION_ALPHA:Number = 0.8;
private const XIMPEL_WEBSITE:String = "http://www.ximpel.net";
private var _errorMessageTimer:Timer;
[Bindable]
private var videoWidth:int = 800;
[Bindable]
private var videoHeight:int = 600;
[Bindable]
private var numberOfOverlayCols:int = 5;
[Bindable]
private var numberOfOverlayRows:int = 5;
[Bindable]
private var dpOverlayCols:Array = new Array(numberOfOverlayCols);
[Bindable]
private var dpOverlayRows:Array = new Array(numberOfOverlayRows);
[Bindable]
private var dpPlayedSubjects:Array;
[Bindable]
private var overlayWidth:int = videoWidth / numberOfOverlayCols;
[Bindable]
private var overlayHeight:int = videoHeight / numberOfOverlayRows;
[Bindable]
private var maxOverlayCels:int = numberOfOverlayCols * numberOfOverlayRows;
The name of the configuration file. You can only set it before XimpelPlayer starts playing.
public var ximpelConfigFileName:String = "ximpel-config.xml";
An indexed array that contains each filter object currently associated with the video display.
public function get interactiveVideoFilters():Array {
return videoDisplay.filters;
}
@private
public function set interactiveVideoFilters(value:Array):void {
videoDisplay.filters = value;
}
The currently loaded playlist.
public function get playlist():XML {
return _videoFeed;
}
The media type of the currently playing item.
public function get currentMediaType():String {
return _currentMediaType;
}
private function finalize(): void { trace("player: final"); }
private function xinit(): void { }
public function init():void {
//trace("player");
_extraQuestionEvaluationTimer = new Timer(EXTRA_QUESTION_EVALUATION_TIME*1000,1);
_errorMessageTimer = new Timer(ERROR_MESSAGE_TIME*1000,1);
_errorMessageTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onErrorMessageComplete);
_extraQuestionEvaluationTimer.addEventListener(TimerEvent.TIMER_COMPLETE, removeExtraQuestionBox);
videoDisplay.addEventListener(VideoEvent.COMPLETE, onVideoComplete);
videoDisplay.addEventListener(CuePointEvent.CUE_POINT, handleCuePoint);
//addEventListener(ScoreEvent.SCORE_CHANGED, updateGameScoreLabelText);
//addEventListener(SubjectEvent.SUBJECT_CHANGED, updateSubjectLabelText);
initLocalConnection();
configService.url = ximpelConfigFileName;
configService.send();
var context:ContextMenu = new ContextMenu();
context.hideBuiltInItems();
var item:ContextMenuItem = new ContextMenuItem(VERSION);
item.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onContextMenuItemSelected);
context.customItems.push(item);
this.parent.contextMenu = context;
contextMenuBox.contextMenu = context;
}
private function initLocalConnection():void {
_incoming_lc = new LocalConnection();
_incoming_lc.connect("minigame_status");
_incoming_lc.client = this;
}
private function configServiceResultHandler(event:ResultEvent):void {
_configFile = event.result as XML;
if(!_configFile.hasOwnProperty("settings")) {
Alert.show("No settings found in " + configService.url);
return;
}
if(_configFile.settings[0].hasOwnProperty("videoDir")) {
_videoDir = _configFile.settings[0].videoDir;
trace("video: " + _videoDir);
}else {
Alert.show("No videoDir found in " + configService.url);
return;
}
if(_configFile.settings[0].hasOwnProperty("assetsDir")) {
_assetsDir = _configFile.settings[0].assetsDir[0];
}else {
_assetsDir = "";
}
if(_configFile.settings[0].hasOwnProperty("extraQuestionDuration")) {
var myExtraQuestionDuration:int = _configFile.settings[0].extraQuestionDuration[0];
if (myExtraQuestionDuration > 0) {
EXTRA_QUESTION_TIME = myExtraQuestionDuration;
}
}
_extraQuestionTimer = new Timer(1000,EXTRA_QUESTION_TIME);
_extraQuestionTimer.addEventListener(TimerEvent.TIMER_COMPLETE, removeExtraQuestionBox);
_extraQuestionTimer.addEventListener(TimerEvent.TIMER, updateExtraQuestionTimerDisplayCount);
if(_configFile.settings[0].hasOwnProperty("scoreMultiplier")) {
var myScoreMultiplier:int = _configFile.settings[0].scoreMultiplier[0];
if (myScoreMultiplier > 0) {
SCORE_MULTIPLIER = myScoreMultiplier;
}
}
if(_configFile.settings[0].hasOwnProperty("videoList") && _configFile.settings[0].videoList[0] != "") {
ximpelService.url = _configFile.settings[0].videoList[0];
_loadVideoPlayListFromConfig = true;
ximpelService.send();
}else {
_loadVideoPlayListFromConfig = false;
//return;
}
_gameScoreMessageArray = new Array();
if (_configFile.hasOwnProperty("scoreMessages")) {
if (_configFile.scoreMessages[0].hasOwnProperty("scoreThreshold")) {
var threshold:ScoreThreshold;
var l:int = _configFile.scoreMessages[0].scoreThreshold.length();
for (var i:int = 0; i < l; i++) {
threshold = new ScoreThreshold();
threshold.message = String(_configFile.scoreMessages[0].scoreThreshold[i].@message);
threshold.underLimit = int(_configFile.scoreMessages[0].scoreThreshold[i].@underlimit);
threshold.upperLimit = int(_configFile.scoreMessages[0].scoreThreshold[i].@upperlimit);
_gameScoreMessageArray.push(threshold);
}
}
}
}
public function toggleFullScreen():void {
//Dit moet een videoDisplay only fullscreen worden
try {
switch (systemManager.stage.displayState) {
case StageDisplayState.FULL_SCREEN:
/* If already in full screen mode, switch to normal mode. */
systemManager.stage.displayState = StageDisplayState.NORMAL;
break;
default:
/* If not in full screen mode, switch to full screen mode. */
systemManager.stage.displayState = StageDisplayState.FULL_SCREEN;
break;
}
} catch (err:SecurityError) {
// ignore
}
}
public function onContextMenuItemSelected(myContextMenuEvent:ContextMenuEvent):void {
//trace("captured context menu event");
if(myContextMenuEvent.currentTarget.caption == VERSION){
var request:URLRequest = new URLRequest(XIMPEL_WEBSITE);
try {
navigateToURL(request, '_blank');
} catch (e:Error) {
//trace("Error occurred:" + e);
}
}
}
Load a playlist. Any previously loaded playlist is replaced by <code>myPlaylist</code>.
If loading of the playlist is succesful, the interactive video will automatically be started.
parameter: myFeed The name of the video feed. Note that the feed must be in the directory that is
defined in the configuration file.
see: #startInteractiveVideo
see: #ximpelConfigFileName
public function setVideoFeed(myFeed:String):void {
ximpelService.url = myFeed;
_loadVideoPlayListFromConfig = false;
trace("service: " + myFeed);
ximpelService.send();
}
private function ximpelServiceResultHandler(event:ResultEvent):void {
trace("player: video");
_videoFeed = event.result as XML;
if(!_loadVideoPlayListFromConfig){
start();
}
}
The XimpelPlayer is started by looking for the first playable video clip in the playlist.
If found, it plays that video clip.
returns: true
if there is a playable video clip in the playlist;
<code>false</code> otherwise.
public function start():Boolean {
_currentSubject = 0;
_currentVideo = 0;
_currentMediaType = "";
_gameScore = 0;
_subjectNameTraceArray = new Array();
_subjectLongnameTraceArray = new Array();
_videoFileTraceArray = new Array();
_overlayArray = new Array();
_clickOverlaySubjectName = new Array();
_overlayCelArray = new Array();
_randomVideoArray = new Array();
_extraQuestionArray = new Array();
_gameScoreArray = [0];
_bonusScoreArray = [0];
videoDisplay.source= "";
videoDisplay.cuePointManager.removeAllCuePoints();
videoDisplay.initialize();
disableCanvases();
myVideoDisplayCanvas.enabled = true;
if(findFirstPlayableVideoForAllSubjects()) {
_gameScore += int(_videoFeed.subject [currentSubject].score);
updateGameScoreLabel();
handlePlayMedia();
dispatchEvent(new InteractiveMediaEvent(InteractiveMediaEvent.NEXT_ITEM));
return true;
}
else {
stop();
return false;
}
}
The XimpelPlayer is stopped manually. Note that the interactive video automatically stops
itself when the end of the playlist is reached.
public function stop():void {
videoDisplay.close();
dispatchEvent(new InteractiveMediaEvent(InteractiveMediaEvent.COMPLETE));
}
private function updateGameScoreLabel():void {
//currentScoreLabel.text = getGameScore();
dispatchEvent(new ScoreEvent(ScoreEvent.SCORE_CHANGED,false,false,getGameScore()));
}
private function updateGameScoreLabelText(scoreEvent:ScoreEvent):void {
//currentScoreLabel.text = scoreEvent.score;
}
private function updateSubjectLabelText(subjectEvent:SubjectEvent):void {
//currentSubjectLabel.text = subjectEvent.subject;
}
An array containing a sequence of played subjects. The sequence is formatted as follows:<br>
<pre>
first subject [array index = 0]
| [array index = 1]
second subject [array index = 2]
| [array index = 3]
...
</pre>
returns: An array containing a sequence of played subjects.
public function outputPlayedSubjects():Array {
dpPlayedSubjects = new Array();
var string:String = "";
var l:int = _subjectNameTraceArray.length;
for (var i:int = 0; i < l; i++) {
if(string != _subjectNameTraceArray[i]) {
string = _subjectNameTraceArray[i];
dpPlayedSubjects.push(_subjectLongnameTraceArray[i].toString());
dpPlayedSubjects.push("|");
}
}
dpPlayedSubjects.push("End");
return dpPlayedSubjects;
}
Returns a message string that is based on the game score. Note that this method is typically
called after the interactive video has stopped. The messages can be set in the configuration file.
returns: A message string that is based on the game score.
public function getGameScoreMessage():String {
var l:int = _gameScoreMessageArray.length;
for (var i:int = 0; i < l; i++) {
if (_gameScore >= _gameScoreMessageArray[i].underLimit) {
if (_gameScoreMessageArray[i].upperLimit == 0) {//0 equals no limit
return _gameScoreMessageArray[i].message;
}else if (_gameScore < _gameScoreMessageArray[i].upperLimit) {
return _gameScoreMessageArray[i].message;
}
}
}
return "No game score message defined";
}
Returns a game score string.
returns: A game score string.
public function getGameScore():String {
return (_gameScore * SCORE_MULTIPLIER).toString();
}
private function findFirstPlayableVideo():Boolean {
var filename:String;
var l:int = _videoFeed.subject [currentSubject].videos.video.length();
while(_currentVideo < l) {
if (_videoFeed.subject [currentSubject].videos.video [currentVideo].@mx-Player.length() &&
_videoFeed.subject [currentSubject].videos.video [currentVideo].@mx-Player) {
return true;
}
_currentVideo++;
}
return false;
}
private function findFirstPlayableVideoForAllSubjects():Boolean {
var l:int = _videoFeed.subject.length();
while(_currentSubject < l) {
if(findFirstPlayableVideo()) {
return true;
}
_currentSubject++;
_currentVideo = 0;
}
return false;
}
private function playVideo():void {
if(videoDisplay.state == VideoEvent.PAUSED) {
dispatchEvent(new InteractiveMediaEvent(InteractiveMediaEvent.RESUME));
}
videoDisplay.play();
}
Plays previous item in playlist (if available).
public function previousItem():void {
if(_subjectNameTraceArray.length < 2) return;
stopOverlayTimers();
//First pop data of currently playing video
_subjectNameTraceArray.pop();
_subjectLongnameTraceArray.pop();
_videoFileTraceArray.pop();
_randomVideoArray.pop();
_gameScore -= _gameScoreArray.pop();
_gameScore -= _bonusScoreArray.pop();
//Now pop and store previous video data
var previousSubject:String = _subjectNameTraceArray.pop();
_subjectLongnameTraceArray.pop();
var previousVideo:String = _videoFileTraceArray.pop();
_gameScore -= _bonusScoreArray.pop();
_currentSubject = _videoFeed.subject.(@name == previousSubject).childIndex();
var l:int = _videoFeed.subject [currentSubject].videos.video.length();
for (var i:int; i < l; i++) {
if (_videoFeed.subject [currentSubject].videos.video[i].attribute("file").length()) {
if (_videoFeed.subject [currentSubject].videos.video[i].@mx-Player == previousVideo) {
_currentVideo = i;
break;
}
}
}
_bonusScoreArray.push(0);
updateGameScoreLabel();
disableCanvases();
handlePlayMedia();
dispatchEvent(new InteractiveMediaEvent(InteractiveMediaEvent.PREVIOUS_ITEM));
}
Plays next item in playlist (if available and possible).
public function nextItem():void {
if (_currentMediaType == MINIGAME_MEDIA) {
onMinigameComplete("minigame_done",0);
} else {
videoDisplay.dispatchEvent(new VideoEvent(VideoEvent.COMPLETE));
}
}
Pauses the current item if playing or resumes the current item if paused.
public function pauseItem():void {
var i:int;
if(videoDisplay.playing) {
videoDisplay.pause();
dispatchEvent(new InteractiveMediaEvent(InteractiveMediaEvent.PAUSE));
}
else {
playVideo();
}
}
private function goToVideoBySubjectName(subjectName:String):void {
if (_videoFeed.subject.(@name == subjectName).videos.video.length()) {
_currentSubject = _videoFeed.subject.(@name == subjectName).childIndex();
_currentVideo = 0;
_gameScoreArray.push(0);
_bonusScoreArray.push(0);
if(findFirstPlayableVideo()) {
_gameScore += int(_videoFeed.subject [currentSubject].score);
_gameScoreArray[_gameScoreArray.length-1] += int(_videoFeed.subject [currentSubject].score);
updateGameScoreLabel();
handlePlayMedia();
dispatchEvent(new InteractiveMediaEvent(InteractiveMediaEvent.NEXT_ITEM));
return;
}
}
stop();
}
private function stopOverlayTimers():void {
videoDisplay.cuePointManager.removeAllCuePoints();
_overlayArray = new Array();
_extraQuestionTimer.reset();
_extraQuestionEvaluationTimer.reset();
_extraQuestionArray = new Array();
_errorMessageTimer.reset();
}
private function clearOverlay():void {
var rowLength:int = dpOverlayRows.length;
var colLength:int = dpOverlayCols.length;
var currentCel:Canvas;
for (var r:int = 0; r < rowLength; r++){
for (var c:int = 0; c < colLength; c++){
currentCel = overlayCel[r][c];
currentCel.visible = false;
currentCel.x = c*overlayWidth;
currentCel.y = r*overlayHeight;
currentCel.width = overlayWidth;
currentCel.height = overlayHeight;
currentCel.alpha = DEFAULT_OVERLAY_ALPHA;
currentCel.setStyle("backgroundColor", DEFAULT_OVERLAY_COLOR);
currentCel.setStyle("backgroundImage", "");
}
}
_overlayCelArray = new Array();
removeOverlayText();
}
private function getPositionFromString(positionString:String):Position {
var myPosition:Position = new Position();
if (positionString.length) {
myPosition.column = (int)(positionString.charAt(0));
myPosition.row = (int)(positionString.charAt(1));
}
return myPosition;
}
private function getSizeFromString(sizeString:String):Size {
var mySize:Size = new Size();
if (sizeString.length) {
mySize.xsize = (int)(sizeString.charAt(0));
mySize.ysize = (int)(sizeString.charAt(1));
}
return mySize;
}
private function getLabelFromString(labelString:String):String {
return labelString.length ? labelString : "";
}
private function checkForOverlay():void {
//Clean up previous overlays and question boxes
clearOverlay();
branchQuestionBox.visible = false;
clearExtraQuestion();
var xmlFeed:XML = _videoFeed.subject [currentSubject].videos.video [currentVideo];
var overlayCount:int = xmlFeed.overlays.overlay.length();
if (overlayCount) {
for (var i:int = 0; i < overlayCount; i++) {
var xmlOverlay:XML = xmlFeed.overlays.overlay[i];
var overlay:Object = new Overlay();
var overlayCels:int = 0;
var tmpPos:Position = new Position();
var tmpSize:Size = new Size();
var tmpLabel:String = "";
//Check for position, size and label for sake of backwards compatibility
tmpPos = getPositionFromString(xmlOverlay.@position);
tmpSize = getSizeFromString(xmlOverlay.@size);
tmpLabel = getLabelFromString(xmlOverlay.@label);
if ((tmpPos.column > -1) && (tmpPos.row > -1) && (tmpSize.xsize > -1) &&
(tmpSize.ysize > -1) && tmpLabel){
overlay.pos.push(tmpPos);
overlay.size.push(tmpSize);
overlay.label.push(tmpLabel);
overlayCels++;
}
while (overlayCels < maxOverlayCels) {
tmpPos = getPositionFromString(xmlOverlay.attribute("position" +
String(overlayCels+1)));
tmpSize = getSizeFromString(xmlOverlay.attribute("size" +
String(overlayCels+1)));
tmpLabel = getLabelFromString(xmlOverlay.attribute("label" +
String(overlayCels+1)));
if ((tmpPos.column > -1) && (tmpPos.row > -1) && (tmpSize.xsize > -1) &&
(tmpSize.ysize > -1) && tmpLabel){
overlay.pos.push(tmpPos);
overlay.size.push(tmpSize);
overlay.label.push(tmpLabel);
}
overlayCels++;
}
if(!overlay.pos.length) {//Check for extended overlay
if(xmlOverlay.overlaycel.length){
overlay = new ExtendedOverlay();
var totalOverlayCels:int = xmlOverlay.overlaycel.length();
for (var j:int = 0; j < totalOverlayCels && j < maxOverlayCels; j++) {
overlay.x[j] = (xmlOverlay.overlaycel[j].attribute("x").length() ?
(Number)(xmlOverlay.overlaycel[j].attribute("x")) : -1);
overlay.y[j] = (xmlOverlay.overlaycel[j].attribute("y").length() ?
(Number)(xmlOverlay.overlaycel[j].attribute("y")) : -1);
overlay.width[j] = (Number)(xmlOverlay.overlaycel[j].attribute("width"));
overlay.height[j] = (Number)(xmlOverlay.overlaycel[j].attribute("height"));
overlay.alpha[j] = (xmlOverlay.overlaycel[j].attribute("alpha").length() ?
(Number)(xmlOverlay.overlaycel[j].attribute("alpha")) : -1);
overlay.hover_alpha[j] =
(xmlOverlay.overlaycel[j].attribute("hover_alpha").length() ?
(Number)(xmlOverlay.overlaycel[j].attribute("hover_alpha")) :
DEFAULT_OVERLAY_HOVER_ALPHA);
overlay.color[j] = (xmlOverlay.overlaycel[j].attribute("color").length() ?
(String)(xmlOverlay.overlaycel[j].attribute("color")) :
DEFAULT_OVERLAY_COLOR);
overlay.hover_color[j] =
(xmlOverlay.overlaycel[j].attribute("hover_color").length() ?
(String)(xmlOverlay.overlaycel[j].attribute("hover_color")) :
DEFAULT_OVERLAY_COLOR);
overlay.image[j] = (String)(xmlOverlay.overlaycel[j].attribute("image"));
overlay.hover_image[j] =
(xmlOverlay.overlaycel[j].attribute("hover_image").length() ?
(String)(xmlOverlay.overlaycel[j].attribute("hover_image")) :
overlay.image[j]);
overlay.label[j] = (String)(xmlOverlay.overlaycel[j].attribute("label"));
}
}
}
if (xmlOverlay.@time.length()) {
if(xmlOverlay.@time) {
overlay.time = xmlOverlay.@time;
}
}
_overlayArray.push(overlay);
if (overlay.time) {
var myCuePoint:Object = { name: "overlay"+String(overlay.time), time: overlay.time };
videoDisplay.cuePointManager.addCuePoint(myCuePoint);
} else {
createOverlay();
}
}
}
}
private function displayExtraQuestion():void {
if (_extraQuestionArray.length) {
clearExtraQuestion();
var extraQuestionCount:int = _extraQuestionArray.shift();
var myCurrentVideo:XML = _videoFeed.subject [currentSubject].videos.video [currentVideo];
extraQuestion.text = myCurrentVideo.question[extraQuestionCount];
extraQuestionBox.visible = true;
extraQuestionBox.alpha = DEFAULT_EXTRA_QUESTION_ALPHA;
_extraQuestionAnswer =
(myCurrentVideo.rightanswer[extraQuestionCount] == "true" ? true : false);
var myDuration:int = myCurrentVideo.question[extraQuestionCount].attribute("duration");
myDuration = (myDuration ? myDuration : EXTRA_QUESTION_TIME);
_extraQuestionTimer.repeatCount = myDuration;
extraQuestionTimerDisplayCount.text = String(_extraQuestionTimer.repeatCount);
_extraQuestionTimer.reset();
_extraQuestionTimer.start();
}
}
private function handleCuePoint(event:CuePointEvent):void {
var myCuePoint:Object;
if (event.cuePointName.indexOf("overlay") > -1){
myCuePoint = { name: "overlay"+String(event.cuePointName), time: event.cuePointTime };
videoDisplay.cuePointManager.removeCuePoint(myCuePoint);
createOverlay();
}else if (event.cuePointName.indexOf("extra") > -1){
myCuePoint = { name: "extra"+String(event.cuePointName), time: event.cuePointTime };
videoDisplay.cuePointManager.removeCuePoint(myCuePoint);
displayExtraQuestion();
}else {
trace("player: Unregistered cuepoint triggered");
}
}
private function createOverlayCels(position:Position, size:Size, subjectName:String,
overlayID:int):void {
var row:int;
var col:int;
if (!((position.column == -1) || (position.row == -1) || (size.xsize == -1) ||
(size.ysize == -1) || (subjectName == ""))) {
var myMaxCols:int;
var myMaxRows:int;
(position.column + size.xsize) > numberOfOverlayCols ?
myMaxCols = numberOfOverlayCols : myMaxCols = position.column + size.xsize;
(position.row + size.ysize) > numberOfOverlayRows ?
myMaxRows = numberOfOverlayRows : myMaxRows = position.row + size.ysize;
for (col = position.column; col < myMaxCols; col++) {
for (row = position.row; row < myMaxRows; row++) {
overlayCel[row][col].visible = true;
_overlayCelArray.push({id: String(row)+","+String(col), subjectName: subjectName,
defaultAlpha: DEFAULT_OVERLAY_ALPHA,
hoverAlpha: DEFAULT_OVERLAY_HOVER_ALPHA,
defaultColor: DEFAULT_OVERLAY_COLOR,
hoverColor: DEFAULT_OVERLAY_COLOR});
}
}
_clickOverlaySubjectName[overlayID] = subjectName;
}
}
private function createExtendedOverlayCels(celX:Number, celY:Number, celWidth:Number, celHeight:Number,
celAlpha:Number, celHoverAlpha:Number, celColor:String, celHoverColor:String, celImage:String,
celHoverImage:String, subjectName:String,
overlayID:int):void {
var currentCel:Canvas;
if (celX > -1 && celY > -1 && celWidth && celHeight && subjectName) {
var row:int = overlayID % numberOfOverlayRows;
var col:int = overlayID / numberOfOverlayCols;
currentCel = overlayCel[row][col];
currentCel.x = celX;
currentCel.y = celY;
currentCel.width = celWidth;
currentCel.height = celHeight;
currentCel.visible = true;
if (celAlpha > -1) currentCel.alpha = celAlpha;
if (celColor) currentCel.setStyle("backgroundColor", celColor);
if (celImage) currentCel.setStyle("backgroundImage", _assetsDir + celImage);
_overlayCelArray.push({id: String(row)+","+String(col), subjectName: subjectName,
defaultAlpha: currentCel.alpha, hoverAlpha: celHoverAlpha,
defaultColor: celColor, hoverColor: celHoverColor,
defaultImage: celImage, hoverImage: celHoverImage});
_clickOverlaySubjectName[overlayID] = subjectName;
}
}
private function createOverlay():void {
if (_overlayArray.length) {
clearOverlay();
if (_overlayArray[0] is Overlay) {
var overlay:Overlay = _overlayArray.shift();
for (var i:int = 0; i < overlay.pos.length; i++){
createOverlayCels(overlay.pos[i], overlay.size[i], overlay.label[i], i);
}
}else if (_overlayArray[0] is ExtendedOverlay) {
var extOverlay:ExtendedOverlay = _overlayArray.shift();
var l:int = extOverlay.x.length;
for (var j:int = 0; j < l; j++){
createExtendedOverlayCels(extOverlay.x[j],extOverlay.y[j],extOverlay.width[j],
extOverlay.height[j],extOverlay.alpha[j],extOverlay.hover_alpha[j],
extOverlay.color[j],extOverlay.hover_color[j],extOverlay.image[j],
extOverlay.hover_image[j],extOverlay.label[j],j);
}
}else {
trace("player: Unknown overlay type");
}
}
}
private function checkForBranchQuestion():void {
var myCurrentVideo:XML = _videoFeed.subject [currentSubject].videos.video [currentVideo];
if(myCurrentVideo.hasOwnProperty("branchquestion")) {
branchQuestion.text = myCurrentVideo.branchquestion;
branchQuestionBox.visible = true;
}
}
private function checkForExtraQuestion():void {
var myCurrentVideo:XML = _videoFeed.subject [currentSubject].videos.video [currentVideo];
if(myCurrentVideo.hasOwnProperty("question")) {
var extraQuestionCount:int = myCurrentVideo.question.length();
for (var i:int = 0; i < extraQuestionCount; i++) {
if(myCurrentVideo.hasOwnProperty("rightanswer")) {
var myTime:int;
if (myCurrentVideo.question[i].attribute("time").length()) {
myTime = myCurrentVideo.question[i].attribute("time");
} else {
myTime = 0;
}
if (myTime == 0) {
_extraQuestionArray.unshift(i);
displayExtraQuestion();
} else {
_extraQuestionArray.push(i);
var myCuePoint:Object = { name: "extra"+String(myTime), time: myTime };
videoDisplay.cuePointManager.addCuePoint(myCuePoint);
}
}
}
}
}
private function handlePlayMedia():void {
myVideoDisplayCanvas.enabled = true;
myViewStack.selectedChild = myVideoDisplayCanvas;
videoDisplay.source = "";
videoDisplay.close();
checkForOverlay();
checkForBranchQuestion();
checkForExtraQuestion();
checkForExtraSegment();
dispatchEvent(new SubjectEvent(SubjectEvent.SUBJECT_CHANGED,false,false,_videoFeed.subject [currentSubject].longname));
//currentSubjectLabel.text = _videoFeed.subject [currentSubject].longname;
var minigameString:String =_videoFeed.subject [currentSubject].videos.video [currentVideo].@minigame;
var fileName:String = _videoFeed.subject [currentSubject].videos.video [currentVideo].@mx-Player;
//check for media type
if (minigameString == "true") {
_currentMediaType = MINIGAME_MEDIA;
} else {
_currentMediaType = VIDEO_MEDIA;
}
if (_currentMediaType == MINIGAME_MEDIA) {
loadMinigame(fileName);
} else {//_currentMediaType == VIDEO_MEDIA
if (fileName.indexOf(MP4_VIDEO_EXTENSION) == fileName.length - MP4_VIDEO_EXTENSION.length){
videoDisplay.source = _videoDir + fileName;
}else {
videoDisplay.source = _videoDir + fileName + FLASH_VIDEO_EXTENSION;
}
videoDisplay.load();
//playVideo();
}
_subjectNameTraceArray.push(_videoFeed.subject [currentSubject].@name);
_subjectLongnameTraceArray.push(_videoFeed.subject [currentSubject].longname);
_videoFileTraceArray.push(_videoFeed.subject [currentSubject].videos.video [currentVideo].@mx-Player);
}
private function disableCanvases():void {
var l:int = myViewStack.numChildren;
for (var i:int = 0; i < l; i++) {
myViewStack.getChildren()[i].enabled = false;
}
}
private function loadMinigame(minigame:String):void {
disableCanvases();
myViewStack.selectedChild = myMinigameCanvas;
myMinigameCanvas.enabled = true;
mySWFLoader.load(minigame+MINIGAME_EXTENSION);
}
Used for local communication by external SWF minigames. When this method is called, the calling
SWF minigame is unloaded and the next item in the playlist is played.
parameter: status The status on which the minigame finished.
parameter: score The score reached in the minigame.
public function onMinigameComplete(status:String,score:int):void {
_currentMediaType = "";
disableCanvases();
mySWFLoader.load();//unload minigame
_gameScore += score;
_bonusScoreArray[_bonusScoreArray.length-1] += score;
updateGameScoreLabel();
myVideoDisplayCanvas.enabled = true;
myViewStack.selectedChild = myVideoDisplayCanvas;
nextItem();
}
private function onVideoComplete(event:VideoEvent):void {
_currentMediaType = "";
var randomVideoString:String =
_videoFeed.subject [currentSubject].videos.video [currentVideo].@random;
var leadsToString:String =
_videoFeed.subject [currentSubject].videos.video [currentVideo].@leadsto;
var repeatString:String =
_videoFeed.subject [currentSubject].videos.video [currentVideo].@repeat;
//stopOverlayTimers();
if (randomVideoString == "true") {
stopOverlayTimers();
_randomVideoArray.push(_currentVideo);
if(_randomVideoArray.length >= _videoFeed.subject [currentSubject].videos.video.length()) {
stop();
}else {
var randomVideo:int;
do{
randomVideo = Math.random() *
(_videoFeed.subject [currentSubject].videos.video.length());
}while(_randomVideoArray.indexOf(randomVideo)>-1);
_currentVideo = randomVideo;
//currentScoreLabel.text = _currentVideo.toString();
handlePlayMedia();
dispatchEvent(new InteractiveMediaEvent(InteractiveMediaEvent.NEXT_ITEM));
}
}
else if (leadsToString) {
stopOverlayTimers();
goToVideoBySubjectName(leadsToString);
}
else if (repeatString == "true") {
if(!(videoDisplay.playing ||
videoDisplay.state == VideoEvent.PAUSED ||
videoDisplay.state == VideoEvent.BUFFERING)) {
stopOverlayTimers();
extraQuestionBox.visible = false;
playVideo();
}
}
else if (_currentVideo + 1 < _videoFeed.subject [currentSubject].videos.video.length()) {
_currentVideo++;
_gameScoreArray.push(0);
_bonusScoreArray.push(0);
stopOverlayTimers();
if((_videoFeed.subject [currentSubject].videos.video [currentVideo].@mx-Player.length() > 0) &&
(_videoFeed.subject [currentSubject].videos.video [currentVideo].@mx-Player)) {
handlePlayMedia();
dispatchEvent(new InteractiveMediaEvent(InteractiveMediaEvent.NEXT_ITEM));
}
else {
nextItem();
}
}
else {
stopOverlayTimers();
stop();
}
}
/*
private function formatPositionToolTip(value:int):String {
//do only handle minutes
var result:String = (value % 60).toString();
if (result.length == 1){
result = Math.floor(value / 60).toString() + ":0" + result;
} else {
result = Math.floor(value / 60).toString() + ":" + result;
}
return result;
}
*/
private function handleDisplayOverlayText(subjectName:String):void {
branchChoice.text = _videoFeed.subject.(@name == subjectName).longname;
displayOverlayText();
}
private function displayOverlayText():void {
branchChoiceBox.visible = true;
}
private function removeOverlayText():void {
branchChoiceBox.visible = false;
}
private function updateExtraQuestionTimerDisplayCount(event:TimerEvent):void {
extraQuestionTimerDisplayCount.text =
String(_extraQuestionTimer.repeatCount - _extraQuestionTimer.currentCount);
}
private function clearExtraQuestion():void {
_extraQuestionTimer.reset();
_extraQuestionEvaluationTimer.reset();
extraQuestionBox.visible = false;
extraQuestionBoxViewStack.selectedIndex = 0;
}
private function removeExtraQuestionBox(event:TimerEvent):void {
clearExtraQuestion();
}
private function evaluateAnswer(userAnswer:Boolean):void {
extraQuestionBoxViewStack.selectedIndex = 1;
_extraQuestionTimer.reset();
if(_extraQuestionAnswer == userAnswer){
extraQuestionEvaluation.text = EXTRA_QUESTION_RIGHT_LABEL;
extraQuestionBox.alpha = DEFAULT_OVERLAY_HOVER_ALPHA;
_gameScore += EXTRA_QUESTION_SCORE;
_bonusScoreArray[_bonusScoreArray.length-1] += EXTRA_QUESTION_SCORE;
updateGameScoreLabel();
}else {
extraQuestionEvaluation.text = EXTRA_QUESTION_WRONG_LABEL;
extraQuestionBox.alpha = DEFAULT_OVERLAY_HOVER_ALPHA;
}
_extraQuestionEvaluationTimer.reset();
_extraQuestionEvaluationTimer.start();
}
private function evaluateAnswerTrue():void {
evaluateAnswer(true);
}
private function evaluateAnswerFalse():void {
evaluateAnswer(false);
}
private function checkForExtraSegment():void {
var extraSegmentString:String =
_videoFeed.subject [currentSubject].videos.video [currentVideo].@extra;
if (extraSegmentString == "true") {
extraSegmentLabel.visible = true;
}else {
extraSegmentLabel.visible = false;
}
}
private function handleClick(id:String):void {
var l:int = _overlayCelArray.length;
for (var i:int = 0; i < l; i++) {
if (_overlayCelArray[i].id == id) {
stopOverlayTimers();
goToVideoBySubjectName(_overlayCelArray[i].subjectName);
return;
}
}
}
private function handleMouseOver(id:String):void {
var l:int = _overlayCelArray.length;
for (var i:int = 0; i < l; i++) {
if (_overlayCelArray[i].id == id) {
handleDisplayOverlayText(_overlayCelArray[i].subjectName);
break;
}
}
var r:int;
var c:int;
for (var j:int = 0; j < l; j++) {
if (_overlayCelArray[j].subjectName == _overlayCelArray[i].subjectName) {
r = _overlayCelArray[j].id.charAt(0);
c = _overlayCelArray[j].id.charAt(2);
overlayCel[r][c].alpha = _overlayCelArray[j].hoverAlpha;
overlayCel[r][c].setStyle("backgroundColor", _overlayCelArray[i].hoverColor);
overlayCel[r][c].setStyle("backgroundImage", _assetsDir + _overlayCelArray[i].hoverImage);
}
}
}
private function removeHoverPropsFromOverlayCels():void {
var r:int;
var c:int;
var l:int = _overlayCelArray.length;
for (var i:int = 0; i < l; i++) {
r = _overlayCelArray[i].id.charAt(0);
c = _overlayCelArray[i].id.charAt(2);
overlayCel[r][c].alpha = _overlayCelArray[i].defaultAlpha;
overlayCel[r][c].setStyle("backgroundColor", _overlayCelArray[i].defaultColor);
overlayCel[r][c].setStyle("backgroundImage", _assetsDir + _overlayCelArray[i].defaultImage);
}
}
private function handleMouseOut(id:String):void {
removeOverlayText();
removeHoverPropsFromOverlayCels();
}
private function onErrorMessageComplete(event:TimerEvent):void {
errorMessageLabel.visible = false;
nextItem();
}
private function handleStateChange(evt:VideoEvent):void {
switch (evt.currentTarget.state) {
case VideoEvent.CONNECTION_ERROR:
//evt.currentTarget.visible = false;
//Alert.show(evt.currentTarget.source, );
errorMessageLabel.text = "Error: Can't load video " + evt.currentTarget.source;
errorMessageLabel.visible = true;
_errorMessageTimer.reset();
_errorMessageTimer.start();
break;
}
//trace(evt.currentTarget.source, evt.state);
}
]]>
</mx:Script>
<mx:ViewStack id="myViewStack" selectedIndex="0" creationPolicy="all">
<mx:Canvas id="myVideoDisplayCanvas" cornerRadius="2" width="800" horizontalScrollPolicy="off"
verticalScrollPolicy="off">
<mx:Box width="{videoWidth}" height="{videoHeight}" x="0" y="0">
<mx:VideoDisplay id="videoDisplay" autoPlay="true" autoRewind="false" width="100%" height="100%"
cuePointManagerClass="mx.controls.videoClasses.CuePointManager"
stateChange="handleStateChange(event);"/>
</mx:Box>
<mx:Box id="contextMenuBox" width="{videoWidth}" height="{videoHeight}" x="0" y="0"/>
<mx:Repeater id="repeaterOverlayRows" dataProvider="{dpOverlayRows}">
<mx:Repeater id="repeaterOverlayCols" dataProvider="{dpOverlayCols}">
<mx:Canvas id="overlayCel" alpha="0.3" width="{overlayWidth}" height="{overlayHeight}"
x="{repeaterOverlayCols.currentIndex*overlayWidth}"
y="{repeaterOverlayRows.currentIndex*overlayHeight}" backgroundSize="100%"
visible="false" buttonMode="true" useHandCursor="true"
click="handleClick(event.currentTarget.instanceIndices.toString())"
mouseOver="handleMouseOver(event.currentTarget.instanceIndices.toString())"
mouseOut="handleMouseOut(event.currentTarget.instanceIndices.toString())"
>
</mx:Canvas>
</mx:Repeater>
</mx:Repeater>
<mx:Panel id="branchQuestionBox" top="5" left="5" width="{videoWidth-10}" height="60" alpha=".8"
horizontalAlign="left" title="{QUESTION_LABEL}:" visible="false">
<mx:filters>
<flash.filters:DropShadowFilter xmlns:flash.filters="flash.filters.*" />
</mx:filters>
<mx:Label id="branchQuestion" text="Branch question" fontSize="13"
paddingLeft="10" paddingTop="30" />
</mx:Panel>
<mx:VBox id="branchChoiceBox" width="{videoWidth}" height="30" top="35" right="30"
horizontalAlign="right" visible="false">
<mx:Label id="branchChoice" text="Branch choice" fontStyle="italic" fontSize="13"
top="0" right="5"/>
</mx:VBox>
<mx:Panel id="extraQuestionBox" width="250" height="180" bottom="70" right="16"
horizontalAlign="center" alpha=".8" verticalAlign="middle" visible="false">
<mx:filters>
<flash.filters:DropShadowFilter xmlns:flash.filters="flash.filters.*" />
</mx:filters>
<mx:ViewStack id="extraQuestionBoxViewStack" width="100%" height="100%">
<mx:VBox horizontalAlign="center">
<mx:Canvas width="100%">
<mx:Text id="extraQuestion" text="Dit is een heel erg lange vraag" fontSize="13"
selectable="false" width="199" height="80" left="8" top="30" />
<mx:Text id="extraQuestionTimerDisplayCount" fontSize="13" selectable="false"
top="30" right="8" />
<mx:HBox width="100%" horizontalGap="80" horizontalAlign="center"
verticalAlign="bottom" y="115">
<mx:Image source="@Embed('assets/button/true.png')" click="evaluateAnswerTrue()"
buttonMode="true" useHandCursor="true"/>
<mx:Image source="@Embed('assets/button/false.png')" click="evaluateAnswerFalse()"
buttonMode="true" useHandCursor="true"/>
</mx:HBox>
</mx:Canvas>
</mx:VBox>
<mx:VBox verticalAlign="middle" horizontalAlign="center">
<mx:Text id="extraQuestionEvaluation" selectable="false" width="90%" fontSize="16"
top="10" textAlign="center"/>
</mx:VBox>
</mx:ViewStack>
</mx:Panel>
<mx:Label id="extraSegmentLabel" text="{EXTRA_SEGMENT_LABEL}" color="#FF1100" fontSize="24" top="0" left="0"
fontWeight="bold" visible="false"/>
<mx:Label id="errorMessageLabel" text="Error message field" color="#FF0000" fontSize="20" bottom="0" left="0"
fontWeight="bold" visible="false"/>
</mx:Canvas>
<mx:Canvas id="myMinigameCanvas" cornerRadius="2" width="800">
<mx:SWFLoader id="mySWFLoader" bottom="0"/>
</mx:Canvas>
</mx:ViewStack>
<!--
<mx:Button id="fullscreenButton" width="36" label="[]" click="toggleFullScreen()"
horizontalCenter="-20" x="0" y="647"/>
-->
</mx:Box>
(C) Æliens
27/08/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.