My problem is that I can't (don't know) make work my switch. Here in my first case, I input "hache", and it doesn't pass trough. Strangely, in my trace(traget); [Object hache] or [Object extincteur] (depending on wich mc I click on) comes out... Why does it don't go trough the first case? I have no clue. I tried removing the " ".
package cem
{
import flash.display.MovieClip;
public class actionObjets{
/*--inventaire--*/
private static var inventaireHache:Boolean = false;
private static var inventaireExtincteur:Boolean = false;
private var objetClique:MovieClip;
public function actionObjets(target) {
this.objetClique = target;
switch(objetClique){
case "hache":
inventaireHache = true;
ajouterInventaire(objetClique);
break;
case "extincteur":
inventaireExtincteur = true;
ajouterInventaire(objetClique);
break;
}
trace(target);
}
private function ajouterInventaire(objetEnlever):void{
objetClique.parent.removeChild(objetClique);
trace(inventaireHache + " - Hache");
trace(inventaireExtincteur + " - Extincteur");
}
}
}
btw, target is the movieClip I clicked on a.k.a. Object extincteur, or Object hache.
The problem is that objetClique isn't a string. You probably want to do something like switch (objetClique.name).
If you want to understand what's going on, rewrite the code this way:
if (objetClique == "hache") {
// ...
} else if (objetClique == "extincteur") {
// ...
}
I hope this illustrates more clearly why the switch doesn't work. objetClique couldn't be equal to the string "hache", because it's not a string. From the looks of it objetClique refers to a DisplayObject and they have a property called name, which is what you want to compare:
if (objetClique.name == "hache") {
// ...
} else if (objetClique.name == "extincteur") {
// ...
}
that code would work, and it's equivalent to a switch that looks like this:
switch (objetClique.name) {
case "hache":
// ...
break;
case "extincteur":
// ...
break;
}
Related
I've been trying to improve the code I use often, and was wondering if there was an easy way to achieve this.
I have a navigation class that defines the objects prior to the constructor (private var exampleScreen:ExampleScreen;).
Based on a string dependency injection for a ChangeScreenTo function (destinationScreen: String), is it possible to grab the defined screen and initialise it (exampleScreen = new ExampleScreen();) dynamically?
Either way, does anyone have any better suggestions than this or my current solution of a switch statement?
Example Code:
package{
public class ScreenController extends MovieClip {
private var currentScreen: DisplayObject;
//SCREENS
private var exampleScreen1:ExampleScreen1;
private var exampleScreen2:ExampleScreen2;
...
public function ScreenController() {
...
}
public function ChangeScreenTo(desinationScreenName: String) {
//REMOVE CURRENT SCREEN
if (currentScreen != null) {
removeChild(currentScreen);
currentScreen = null;
}
switch (destinationScreenName) {
case "exampleScreen1":
exampleScreen1 = new ExampleScreen1();
break;
case "exampleScreen2":
exampleScreen2 = new ExampleScreen2();
break;
...
}
mcDestinationScreen = this[(destinationScreenName)];
addChild(mcDestinationScreen);
currentScreen = mcDestinationScreen;
}
}
}
May be this is better:
public function ChangeScreenTo(desinationScreenName: String) {
//REMOVE CURRENT SCREEN
if (currentScreen != null) {
removeChild(currentScreen);
currentScreen = null;
}
switch (destinationScreenName) {
case "exampleScreen1":
currentScreen = exampleScreen1 = new ExampleScreen1();
break;
case "exampleScreen2":
currentScreen = exampleScreen2 = new ExampleScreen2();
break;
...
}
addChild(currentScreen);
}
I'm trying to call the punch function from my player class inside another class but for some reason it gives me this error:
1180: Call to a possibly undefined method Punch.
I'm not sure why it gives me this error. I even made the functions public.
This is the class where i am calling it from:
package
{
public class Player extends MovieClip
{
public function Player()
{
stage.addEventListener(KeyboardEvent.KEY_DOWN,KeyDown);
stage.addEventListener(KeyboardEvent.KEY_DOWN,KeyPressed);
addEventListener(Event.ENTER_FRAME,Update);
}
function KeyPressed(event:KeyboardEvent):void
{
//If on floor
if (CanJump)
{
//If A key is down
if (event.keyCode == 65)
{
//Punch
Punch(true);
}
}
}
function Update(event:Event)
{
//Do stuff
}
}
}
and this is what I am trying to call:
package
{
public class ComboSequence extends ComboHandler
{
public function ComboSequence(clipName:String, par:BaseObject, _oList:ObjectList)
{
// constructor code
super(clipName, par, _oList);
}
public function Punch(PunchKey:Boolean)
{
if (currentAttack != null)
{
if (Recovery <= 0 && FollowUpTime > 0)
{
currentAttack = currentAttack.GetNextAttack(PunchKey);
if (currentAttack != null)
{
SetAnimation(currentAttack.animName);
Recovery = currentAttack.Recovery;
FollowUpTime = currentAttack.Recovery + 25;
}
}
}
if (FollowUpTime > 0)
{
FollowUpTime--;
}
else
{
currentAttack = null;
}
if (Recovery > 0)
{
Recovery--;
}
}
}
}
When you call Punch() on its own inside the player class, ActionScript is looking for a Player.Punch() method. Your method is on the ComboSequence class. You're probably trying to do something like this:
var comboSequence:ComboSequence = new ComboSequence();
comboSequence.Punch()
Keep in mind that while this code will run, it probably won't do what you want it to do. I guess you want to keep an instance of ComboSequence in your player object. If that doesn't make sense to you, it would be a good idea to do some background reading on ActionScript and object-oriented programming in general.
You need to import ComboSequence into the Player class and call Punch though that like
ComboSequence.Punch. andypaxo is right in his post, you'd need to instantiate it somewhere within the Player class.
One note about your code, though, you should not name functions with a capital letter. Class names typically start with a capital letter, but not the methods within.
package
{
import ComboSequence; //you may need the package path if its in a package, something like com.classes.ComboSequence, where com.classes is the folder that ComboSequence is saved.
public class Player extends MovieClip
{
public function Player()
{
stage.addEventListener(KeyboardEvent.KEY_DOWN,KeyDown);
stage.addEventListener(KeyboardEvent.KEY_DOWN,KeyPressed);
addEventListener(Event.ENTER_FRAME,Update);
}
function KeyPressed(event:KeyboardEvent):void
{
//If on floor
if (CanJump)
{
//If A key is down
if (event.keyCode == 65)
{
//Punch
ComboSequence.Punch(true);
}
}
}
function Update(event:Event)
{
//Do stuff
}
}
}
also, regarding your "missing rightParen" error, rightParen means right parenthesis, or ), leftParen would be (. That error means you are missing a ) somewhere. Often times it can mean you added an extra one somewhere, thus closing a section of parenthesis you didn't mean to close, which would leave one unpaired parenthesis somewhere.
I'm not really expert on OOP and as3 now. I'm making inventory system that will handle this things:
*when player collide with an "item", it will get it and send to the inventory array, etc...
here is the Player class constructor
as you can see i write item's instance name manually: "silver_key"
public function Player(player:MovieClip,loot:MovieClip,place:MovieClip)
{
// constructor code
_player = player;
silver_key = loot;//the item
_inventory = new InventorySystem(place);//InventorySystem Class
_player.addEventListener(Event.ENTER_FRAME,on_enter_frame);
addEventListener(EventDemo.EVENT_DEFAULT,onEvent);//custom event listener
}
This is the functions relative to it:
private function on_enter_frame(e:Event):void
if (_player.hitTestObject(silver_key))//check collision between player and item
{
dispatchEvent(new EventDemo(EventDemo.EVENT_DEFAULT));
}
private function onEvent(e:EventDemo)
{
_inventory.getitem(_loot);//function use in InventorySystem for array.push
removeEventListener(EventDemo.EVENT_DEFAULT,onEvent);//removes the listener when the item was sent to array
}
now my question is how can i be able to create a lot of items without manually writing their instance name. Thanks.
ps: if you still can't understand please comment.
To put it simply:
object["string_name"] = value
For a more thorough explanation, read on...
You need explicit names for each item, but you want to dynamically define those items without knowledge of what it could be. You can store this in a number of ways, but a basic Array or Object should work fine.
It looks like you were creating a movieclip to represent the player. As a class, the instantiation of the player class could itself be that movieclip, but be aware that MovieClips carry a lot of timeline baggage that can slow you down. For a more succinct/lightweight player class, extend Sprite and write your own properties/methods.
For example, let's imagine this is what a Silver Key object looks like:
item:Object = {
"name":"Silver Key",
"count":1,
"weight":3,
"icon":"silver_key.jpg"
}
In one object, we can define a name property to be whatever we want that type of item to be, as well as other pertinent properties that describe that item. Now, all we need to do is keep a list of saved items in the player class itself.
Player Class
package {
public dynamic class Player extends Sprite {
import flash.events.*;
import flash.display.*;
public var inventory:Object = {};
public function Player() {
addEventListener(Event.ENTER_FRAME, tick);
}
public function tick(e:Event):void {
// ENTER_FRAME stuff
}
public function loot(item:Object) {
if (inventory.hasOwnProperty(item.name)) {
inventory.item.count++
trace("You now have " + inventory.item.count + " " + item.name + "'s!");
} else {
inventory[item.name] = item;
trace("You have picked up a " + item.name)
}
}
public function drop(item:Object) {
if (inventory.hasOwnProperty(item.name)) {
inventory.item.count--
if (inventory.item.count == 0) {
trace("You no longer have " + item.name);
delete(inventory[item.name]);
} else {
trace("You now have one less " + item.name + ".");
}
}
}
}
}
Example Implementation
var player:Player = new Player();
player.loot(item);
// traces "You picked up a Silver Key"
player.drop(item);
// traces "You no longer have Silver Key"
This is a simple way of doing it, and truthfully, you may want to expand on it with your own item & inventory classes, as well as data sanitization/checking to prevent a corrupted inventory.
Update: "More than likely, you'll create a prototype of each item."
Here's what one could look like.
package {
public class ItemDefinition extends Object {
public var name:String = "Unnamed Item";
public var count:int = 1;
public var weight:int = 0;
public var icon:String = "unnamed.jpg";
public function ItemDefinition(Properties:Object) {
// By passing in an object, we can define only the properties we want to change.
for (var Name:String in Properties) {
// Only property names that match will overwrite the defaults.
if (this.hasOwnProperty(Name)) {
this[Name] = Properties[Name]
}
}
}
}
}
What's cool about this, is that we can define any number of properties and in any order without fear of adding a bogus value that could mess us up later. Furthermore, if we want to add a new property to what defines a Item, just add it as a public var at the top.
Next, we might define all of our items once at the top of our document, using a new ItemDefinition object.
var itemDefinitions:Object = {
'Silver Key':new Item({name:"Silver Key", icon:"silver_key.jpg", weight:3}),
'Gold Key':new Item({weight:10, name:"Gold Key", icon:"gold_key.jpg"}),
'Iron Key':new Item({icon:"iron_key.jpg", weight:2, name:"Iron Key"})
}
function populateItems(itemName:String, count:int = 20) {
if (itemDefinitions.hasOwnProperty(itemName)) {
for (var i:int = 0; i < count; i++) {
var item:MovieClip = new MovieClip();
item.x = randomNumber(0, this.loaderInfo.width);
item.y = randomNumber(0, this.loaderInfo.height);
item["itemDefinition"] = itemName;
}
} else {
trace(itemName + " is an invalid item.");
}
}
function randomNumber(low:Number=0, high:Number=1):Number {
/* Returns a random number between the low and high values given. */
return Math.floor(Math.random() * (1+high-low)) + low;
}
As you can see, I've added a couple helper functions to spit out those extra items on screen (randomly). Obviously, we'd need to have an addChild, and image loading, but that's really something you should implement.
Finally, we'll revise our loot call to pass the itemDefinition...
player.loot(itemDefinitions[item.itemDefinition]);
removeChild(item);
Worlds of possibilities. You'll likely make something far more robust which addresses the needs of your game, so this is only one way you might do it.
I'm trying to get away from using code on the main timeline but I'm struggling to understand how .as files and .fla files interact. For example, I'm trying to figure out how to pass a variable from the main timeline, to a public function, do some stuff to that variable and pass it back to the main timeline. I have an input text box on the frame and a simple button with a listener. I want to be able to input 00000 00 into the text box, and have 0.00 returned. Below is my code:
import flash.events.MouseEvent;
import convertToDecimal;
var inputText:String;
var outputText:String;
submit_btn.addEventListener(MouseEvent.CLICK, submit);
function submit(e:MouseEvent):void
{
inputText = input_txt.text;
new convertToDecimal(inputText);
trace();
}
And here is the public function:
package
{
import flash.sampler.StackFrame;
import flash.events.MouseEvent;
import fl.controls.Button;
public class convertToDecimal
{
public function convertToDecimal(stringParmter:String)
{
var rex:RegExp = /[\s\r\n]+/gim;
stringParmter = stringParmter.replace(/^\s+|\s+$/g, '');
stringParmter = stringParmter.replace(rex,'.');
stringParmter = stringParmter.replace(/^0+(?!\.|$)/, '');
if ((stringParmter == "-----.--") || (stringParmter == "0"))
{
stringParmter = " 00";
}
}
}
}
This is probably a really noob question but any help is appreciated.
If you have class, in order to use it, you must construct its "copy" and assign it to the variable. Constructing your class is really easy:
new convertToDecimal(inputText); // does the constructing job
But what happen next? When your program goes to the next line, you constructed class will be loosed! You must assign it to variable, in order to keep it in memory:
var yourVariableName:convertToDecimal = new convertToDecimal(inputText);
Now you have your "copy" of class. OOP paradigm is good because you can create tons of "copies" really easily and then, each "copy" will live by its own live.
Now back to your question. It's not a secret that adding your code to the timeline is bad. Instead attach your class to your project and change it this way:
package
{
import flash.sampler.StackFrame;
import flash.events.MouseEvent;
import fl.controls.Button;
public class Main
{
public function Main()
{
submit_btn.addEventListener(MouseEvent.CLICK, submit);
}
private function submit(e:MouseEvent):void
{
var inputText:String = input_txt.text;
inputText = convertToDecimal(inputText);
trace(inputText);
}
private function convertToDecimal(stringParmter:String):String
{
var rex:RegExp = /[\s\r\n]+/gim;
stringParmter = stringParmter.replace(/^\s+|\s+$/g, '');
stringParmter = stringParmter.replace(rex, '.');
stringParmter = stringParmter.replace(/^0+(?!\.|$)/, '');
if ((stringParmter == "-----.--") || (stringParmter == "0"))
{
stringParmter = " 00";
}
return stringParmter;
}
}
}
Parameters of simple types are passed by value, so in order to return a changed String, make your public function return String:
public function convertToDecimal(stringParmter:String):String {...}
Then, when you come up with a value that you want to be available outside, put a return <the value>; statement in your function. In order to capture the value returned from a function, assign it to a variable, the same one that's passed into it can be used.
stringParameter=convertToDecimal(stringParmter);
Also, if your AS3 file contains only the function, you can avoid wrapping it into a class, and declare directly "public function...".
package
{
public function convertToDecimal(stringParmter:String):String
{
var rex:RegExp = /[\s\r\n]+/gim;
var s:String;
s = stringParmter.replace(/^\s+|\s+$/g, '');
s = s.replace(rex,'.');
s = s.replace(/^0+(?!\.|$)/, '');
if ((s == "-----.--") || (s == "0"))
{
s = " 00";
}
return s;
}
}
Sorry if this question has already been answered but I can't seem to find any relevant examples online. I basically have a class which loads a set of MovieClip objects and provides accessor functions to return them.
public function getMovieClip( mc:MovieClip ):Boolean
{
if( allFilesLoaded )
{
mc = fileLoader.content;
return true;
}
else
{
return false;
}
}
Obviously this doesn't work, but it gives an idea of what I'm trying to do. I want to return a MovieClip to the calling code only if the object has been loaded.
You can’t modify the parameter like that. Instead, return the MovieClip like this:
public function getMovieClip():MovieClip
{
if ( allFilesLoaded )
{
return fileLoader.content;
}
else
{
return null;
}
}
And then you can just use it like this, even with reading the MovieClip:
var mc:MovieClip; // defined somewhere
// later...
if ( ( mc = x.getMovieClip() ) )
{
// all files were loaded and mc is not null.
}
else
{
// files were not loaded and mc is null.
}
Try this:
// change the allFilesLoaded value to view the other result
var allFilesLoaded:Boolean = true;
trace(getMovieClip(null) );
function getMovieClip( mc:* ):*
{
if( allFilesLoaded )
{
mc = new MovieClip();
return mc;
}
else
{
return false;
}
}
The asterisk denotes that the type of data that is returned is unknown, and we could both be Boolean as a MovieClip.
If allFilesLoaded then returns the mc (MovieClip) otherwise it returns false (Boolean).
Hope that helps.