inherit
201984
0
Sept 11, 2023 1:23:07 GMT -8
P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓
Using My Talents Elsewhere
3,314
November 2013
pastuleo23
|
Post by P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓ on Jul 26, 2014 8:53:26 GMT -8
I'll give it a thorough looking over Sunday evening. I installed the Monetary System plugin yesterday evening to circumvent issue #1 and played around with several of the new features. I appreciate it.
|
|
inherit
201984
0
Sept 11, 2023 1:23:07 GMT -8
P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓
Using My Talents Elsewhere
3,314
November 2013
pastuleo23
|
Post by P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓ on Jul 27, 2014 0:17:39 GMT -8
I'll give it a thorough looking over Sunday evening. I installed the Monetary System plugin yesterday evening to circumvent issue #1 and played around with several of the new features. Try this one: Animal Keeper (16).pbp (33.88 KB) Should have got rid of some bugs, have your suggestions, and I'm currently working on modifying animal happiness. However it's a lengthy process.
|
|
inherit
168679
0
Nov 18, 2012 17:03:07 GMT -8
Virgil Sovereign
Latet anguis in herba.
686
July 2011
syonidv
|
Post by Virgil Sovereign on Jul 27, 2014 14:55:49 GMT -8
P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓: It looks like you've addressed most of the issues. Quick work! Some remaining issues in revision 16: - regarding the previous issue of a large "No Image" background: my suggestion would be that if the user chooses "No Image" as a background, the plugin should leave the background transparent
- regardless of the background I choose, when I refresh the page and open up "Field Backgrounds" under the images tab, the background thumbnail has reverted to "No Image" and the plugin pops up a message box indicating that "The image link provided was not valid." The same problem occurs for all other types of backgrounds as well.
- the default poos are huge! This isn't a bug; I just found it funny. I came back and one of my wee dragons had laid a poo bigger than he was.
- while testing revision 13 of your plugin I noticed that one of my dragons, while still present on the field, wasn't listed in the ledger or on the play tab. He came back when I updated to revision 15 and refreshed. I don't know if this was because of a bug fix or simply because I refreshed the page. I figured I'd notify you just in case.
- the animation is a cool feature. It took me quite a while to figure out the way you've worked it.
I realize now that you're actually using the "rest" parameter as a clock resolution for an event queue. If the "rest" is T seconds, the plugin appears to update the queue every T seconds by pushing as many events (movement sequences) into the queue as needed to update the animation to the current timestep. (Actually, this behaviour seems to have changed between rev. 13 and rev. 15. In rev. 13, the plugin would queue multiple motions per clock cycle; in rev. 15 it appears to only queue one motion per clock cycle, regardless of lag.)
This system is highly unorthodox and may be problematic for a few reasons. Firstly, if the clock resolution is too low, animations with multiple rapid events tend to "lurch". For example, I changed my "circle" motion sequence to
100 0 100 97 26 100 87 50 100 71 71 100 50 87 100 26 97 100 0 100 100 -26 97 100 -50 87 100 -71 71 100 -87 50 100 -97 26 100 -100 0 100 -97 -26 100 -87 -50 100 -71 -71 100 -50 -87 100 -26 -97 100 0 -100 100 26 -97 100 50 -87 100 71 -71 100 87 -50 100 97 -26 100
I expected a "rest" of 1000 ms to insert either a single 1-second pause at the end of the sequence, or possibly a 1-second pause after every movement in the sequence. As it turns out, the plugin runs one movement every second because this is the clock resolution.
Any motion whose completion time isn't a multiple of the clock resolution is going to have an arbitrary gap between its completion and the beginning of the next motion. I suppose this is why you called the parameter "rest", but the fact that you're assigning a fixed number (like 1000) to "rest" would normally indicate that the rest period is exactly this long. Letting T be the clock resolution, R be the resting period, and L be the movement time, the current rest period is given by
R = nT - L
for the smallest integer value of n for which R is non-negative.
If I might suggest: simply eliminate the "rest" parameter altogether. It's bound to confuse admins. Instead, have all your movement queues running off a single timer with a high resolution (say, 10 ms) that starts new motions as needed. And for rest period between motions, instruct admins to insert
0 0 [pause length]
commands into the motion sequence wherever they want pauses in the motion.
- when the size/animation parameters are viewed for a particular animal, they should ideally reflect the current state of the animal. For example, if an animal is set to "medium" size, with a height of 90px, and has movement type "Line", the various fields and dropdowns should show "medium", "90", "Line" as soon as the panel is opened. Currently the controls always appear in their "unset" state.
- the small/medium/large "Auto" size feature is highly unorthodox. I think I've figured it out. If either the width or height field is set, and one of the sizes is selected in the dropdown, the plugin sets the selected size to the specified dimensions when "Save" is clicked. If neither field is set when "Save" is clicked, the plugin instead loads whatever dimensions were last "saved" for the selected size and uses them as the dimensions of the current animal.
I suspect users will find this extremely confusing. My suggestion would be to eliminate the "Auto" dropdown altogether and include a "Most Recent Sizes" feature similar to the "Most Recent Backgrounds" that would contain the 3-4 most recently set sizes. If only height or width is set, the most recent size entry would be listed as "height 200" or "width 75". If both are set together, the entry would be listed as "width 75, height 200", etc. And if neither is set (i.e. the user is using the natural dimensions of the image), the entry would be listed as "natural dimensions".
- I can't seem to influence the animals' happiness in any way. Brushing, feeding, playing, etc. don't seem to have any effect. This may just be because you haven't implemented the feature yet.
- the "Pet" and "Wash" features don't appear to work. Again, this is probably because you haven't implemented them yet.
- regarding your response to the "spam click" bug: I realize you need to deal with spam clicks, but having errors declared on the JS console in release code is not good practice. And if you're using unchecked errors to control the flow of execution, that's a definite no-no. Won't a return statement somewhere suffice?
- regarding your response to the "Custom User Options" multi-form: just so we're on the same page, the following figure shows what I'm talking about
Why not have just one set of options grouped under the header bar "Custom User Options"?
That's it for bugs. Some suggestions:
- currently there's no action assigned to clicking on an animal except to retain the information popup for the animal. I believe it would be more useful if clicking on an animal opened up its "Play" interface.
- although I like the info popups when mousing over animals, it's customary to have such popups placed beside the animal rather than in the center of the application. The other problem with having the popup in the center is that if the animal happens to be in the center, the popup obscures it. I would recommend having the popup placed to the right of the animal, or if not enough space is available inside the application space, to the left of the animal.
- you once suggested that when placing an animal, you'd make the animal itself the cursor. I thought this was an excellent idea. Currently you're using the "Add" image as a cursor, and the animal doesn't appear particularly close to the center of the cross, which most users would presume is the hotspot. My recommendation is definitely to use the animal itself as the cursor so that users know exactly where they're placing an animal.
- it would be nice if a "move" command (in addition to the "remove" command) was present in the ledger for existing animals. It would allow users to move existing animals to new positions rather than having to remove them and re-buy them.
- it would be nice if a toy could be "applied" to a specific animal by dragging it onto that animal. Currently you have the toy interaction as a general statement. Perhaps if you make the interaction statement for a toy something like You threw the ball to \name. \HeShe caught it and it made \himher happy. where \name was automatically replaced by the name of the animal, and \HeShe, \himher, and other similar tokens would be replaced by gender-specific pronouns when viewed by the user. For a male, e.g. You threw a ball to Fido. He caught it and it made him happy. The admin could also specify how much an animal's happiness increased as a result of the action, and they could use these variables as tokens in the interaction description for the toy if they wanted to. For example,
You fed \name a chicken. \HisHer happiness increased by \change to \newhappiness.
would translate to
You fed Cyrene a chicken. Her happiness increased by 5 to 58.
Definitely spend some time thinking about how the various actions affect happiness levels. A huge part of the fun of the plugin will be the simulation aspect: taking all the actions necessary to keep animals happy. Also, if I might boldly suggest, it would be an excellent addition if you built in some kind of overriding "score" or metric to track a user's performance. For example, consider the basic set of rules: - an animal starts with h happiness
- an animal must be fed once every x days or else will suffer a drop of 3d happiness every day, where d is the number of days since the animal was last fed
- an animal must be washed ... etc.
- an animal must be played with ... etc.
- an animal with zero happiness is considered "miserable"; an animal that stays miserable for y days dies
- an animal that reaches a natural lifespan of z animal years dies a natural death
- the keeper's score for an animal depends on the animal's happiness when it dies; if an animal dies completely happy, +w points; if an animal dies miserable, -w points, etc.
- if a keeper sells/gifts an animal, they incur a penalty if the animal is unhappy, but no bonus if the animal is happy (to prevent point farming)
- a keeper's "keeper score" is their total score over all animals they raise. A keeper who raises many animals and keeps them happy until a natural death will have a high score. A keeper who does not keep his/her animals happy will have a low score
- etc., etc.
The admins will be able to configure various aspects of the simulation such as intervals for feeding, playing, etc., happiness decay rates, scores, etc., and the effect of various actions on animals' happiness. An overall score will give users an incentive to keep their animals happy, and by extension give purpose to all the actions that affect happiness. You would also have an opt out option for admins not interested in scoring.
That's all of my suggestions for now.
|
|
inherit
201984
0
Sept 11, 2023 1:23:07 GMT -8
P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓
Using My Talents Elsewhere
3,314
November 2013
pastuleo23
|
Post by P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓ on Jul 27, 2014 19:55:56 GMT -8
P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓: It looks like you've addressed most of the issues. Quick work! Some remaining issues in revision 16: - regarding the previous issue of a large "No Image" background: my suggestion would be that if the user chooses "No Image" as a background, the plugin should leave the background transparent
- regardless of the background I choose, when I refresh the page and open up "Field Backgrounds" under the images tab, the background thumbnail has reverted to "No Image" and the plugin pops up a message box indicating that "The image link provided was not valid." The same problem occurs for all other types of backgrounds as well.
- the default poos are huge! This isn't a bug; I just found it funny. I came back and one of my wee dragons had laid a poo bigger than he was.
- while testing revision 13 of your plugin I noticed that one of my dragons, while still present on the field, wasn't listed in the ledger or on the play tab. He came back when I updated to revision 15 and refreshed. I don't know if this was because of a bug fix or simply because I refreshed the page. I figured I'd notify you just in case.
- the animation is a cool feature. It took me quite a while to figure out the way you've worked it.
I realize now that you're actually using the "rest" parameter as a clock resolution for an event queue. If the "rest" is T seconds, the plugin appears to update the queue every T seconds by pushing as many events (movement sequences) into the queue as needed to update the animation to the current timestep. (Actually, this behaviour seems to have changed between rev. 13 and rev. 15. In rev. 13, the plugin would queue multiple motions per clock cycle; in rev. 15 it appears to only queue one motion per clock cycle, regardless of lag.)
This system is highly unorthodox and may be problematic for a few reasons. Firstly, if the clock resolution is too low, animations with multiple rapid events tend to "lurch". For example, I changed my "circle" motion sequence to
100 0 100 97 26 100 87 50 100 71 71 100 50 87 100 26 97 100 0 100 100 -26 97 100 -50 87 100 -71 71 100 -87 50 100 -97 26 100 -100 0 100 -97 -26 100 -87 -50 100 -71 -71 100 -50 -87 100 -26 -97 100 0 -100 100 26 -97 100 50 -87 100 71 -71 100 87 -50 100 97 -26 100
I expected a "rest" of 1000 ms to insert either a single 1-second pause at the end of the sequence, or possibly a 1-second pause after every movement in the sequence. As it turns out, the plugin runs one movement every second because this is the clock resolution.
Any motion whose completion time isn't a multiple of the clock resolution is going to have an arbitrary gap between its completion and the beginning of the next motion. I suppose this is why you called the parameter "rest", but the fact that you're assigning a fixed number (like 1000) to "rest" would normally indicate that the rest period is exactly this long. Letting T be the clock resolution, R be the resting period, and L be the movement time, the current rest period is given by
R = nT - L
for the smallest integer value of n for which R is non-negative.
If I might suggest: simply eliminate the "rest" parameter altogether. It's bound to confuse admins. Instead, have all your movement queues running off a single timer with a high resolution (say, 10 ms) that starts new motions as needed. And for rest period between motions, instruct admins to insert
0 0 [pause length]
commands into the motion sequence wherever they want pauses in the motion.
- when the size/animation parameters are viewed for a particular animal, they should ideally reflect the current state of the animal. For example, if an animal is set to "medium" size, with a height of 90px, and has movement type "Line", the various fields and dropdowns should show "medium", "90", "Line" as soon as the panel is opened. Currently the controls always appear in their "unset" state.
- the small/medium/large "Auto" size feature is highly unorthodox. I think I've figured it out. If either the width or height field is set, and one of the sizes is selected in the dropdown, the plugin sets the selected size to the specified dimensions when "Save" is clicked. If neither field is set when "Save" is clicked, the plugin instead loads whatever dimensions were last "saved" for the selected size and uses them as the dimensions of the current animal.
I suspect users will find this extremely confusing. My suggestion would be to eliminate the "Auto" dropdown altogether and include a "Most Recent Sizes" feature similar to the "Most Recent Backgrounds" that would contain the 3-4 most recently set sizes. If only height or width is set, the most recent size entry would be listed as "height 200" or "width 75". If both are set together, the entry would be listed as "width 75, height 200", etc. And if neither is set (i.e. the user is using the natural dimensions of the image), the entry would be listed as "natural dimensions".
- I can't seem to influence the animals' happiness in any way. Brushing, feeding, playing, etc. don't seem to have any effect. This may just be because you haven't implemented the feature yet.
- the "Pet" and "Wash" features don't appear to work. Again, this is probably because you haven't implemented them yet.
- regarding your response to the "spam click" bug: I realize you need to deal with spam clicks, but having errors declared on the JS console in release code is not good practice. And if you're using unchecked errors to control the flow of execution, that's a definite no-no. Won't a return statement somewhere suffice?
- regarding your response to the "Custom User Options" multi-form: just so we're on the same page, the following figure shows what I'm talking about
Why not have just one set of options grouped under the header bar "Custom User Options"?
That's it for bugs. Some suggestions:
- currently there's no action assigned to clicking on an animal except to retain the information popup for the animal. I believe it would be more useful if clicking on an animal opened up its "Play" interface.
- although I like the info popups when mousing over animals, it's customary to have such popups placed beside the animal rather than in the center of the application. The other problem with having the popup in the center is that if the animal happens to be in the center, the popup obscures it. I would recommend having the popup placed to the right of the animal, or if not enough space is available inside the application space, to the left of the animal.
- you once suggested that when placing an animal, you'd make the animal itself the cursor. I thought this was an excellent idea. Currently you're using the "Add" image as a cursor, and the animal doesn't appear particularly close to the center of the cross, which most users would presume is the hotspot. My recommendation is definitely to use the animal itself as the cursor so that users know exactly where they're placing an animal.
- it would be nice if a "move" command (in addition to the "remove" command) was present in the ledger for existing animals. It would allow users to move existing animals to new positions rather than having to remove them and re-buy them.
- it would be nice if a toy could be "applied" to a specific animal by dragging it onto that animal. Currently you have the toy interaction as a general statement. Perhaps if you make the interaction statement for a toy something like You threw the ball to \name. \HeShe caught it and it made \himher happy. where \name was automatically replaced by the name of the animal, and \HeShe, \himher, and other similar tokens would be replaced by gender-specific pronouns when viewed by the user. For a male, e.g. You threw a ball to Fido. He caught it and it made him happy. The admin could also specify how much an animal's happiness increased as a result of the action, and they could use these variables as tokens in the interaction description for the toy if they wanted to. For example,
You fed \name a chicken. \HisHer happiness increased by \change to \newhappiness.
would translate to
You fed Cyrene a chicken. Her happiness increased by 5 to 58.
Definitely spend some time thinking about how the various actions affect happiness levels. A huge part of the fun of the plugin will be the simulation aspect: taking all the actions necessary to keep animals happy. Also, if I might boldly suggest, it would be an excellent addition if you built in some kind of overriding "score" or metric to track a user's performance. For example, consider the basic set of rules: - an animal starts with h happiness
- an animal must be fed once every x days or else will suffer a drop of 3d happiness every day, where d is the number of days since the animal was last fed
- an animal must be washed ... etc.
- an animal must be played with ... etc.
- an animal with zero happiness is considered "miserable"; an animal that stays miserable for y days dies
- an animal that reaches a natural lifespan of z animal years dies a natural death
- the keeper's score for an animal depends on the animal's happiness when it dies; if an animal dies completely happy, +w points; if an animal dies miserable, -w points, etc.
- if a keeper sells/gifts an animal, they incur a penalty if the animal is unhappy, but no bonus if the animal is happy (to prevent point farming)
- a keeper's "keeper score" is their total score over all animals they raise. A keeper who raises many animals and keeps them happy until a natural death will have a high score. A keeper who does not keep his/her animals happy will have a low score
- etc., etc.
The admins will be able to configure various aspects of the simulation such as intervals for feeding, playing, etc., happiness decay rates, scores, etc., and the effect of various actions on animals' happiness. An overall score will give users an incentive to keep their animals happy, and by extension give purpose to all the actions that affect happiness. You would also have an opt out option for admins not interested in scoring.
That's all of my suggestions for now. ;)1
1: as for number 1 I already have it set up so that it won't let you choose the no-image image (provided by the admin) but alert that the url is invalid and do nothing. 2: number 1 fixes this 3: Yeah changing size is on my list 4: Prob Rev 13 5: I got really confused on how to make the structure simple and yet feasible. I know that the polling could be a problem. However I couldn't think of a polling design at the time that would allow to 'restart' the group of movements. I will look into it. 6: Very true, I also thought about adding a preview box of how it's going to look before you submit your changes. 7: I will try to add an OR: in there to make it more clear. However I can't just save everyone's data willy nilly cause that would just crank up the key space. I do understand the concern, however aint nobody got time for dat. If neither are set, then it goes by the last height/width and usually defaults to what the admin says is max. 8: I personally just implemented increasing happiness. However working on ideas on decreasing happiness. 9: The pet and wash work on my test field, probably just a glitch in your key data from rev13 or less 10: I didn't want to do it how I did, however I could not find another way to prevent execution of the next animation; 11:Planned on it 1: A fast moving animal wouldn't be readable then. 2: Would take referencing height,width of image and comparing to current position and factoring the play field height and width and displaying it left or right and counteracting the length of the popup bubble via the size of the description and factoring in the height whether it should be displayed higher. Simplicity is better for me. 3: My positoning is a little off, will look into 4: you don't have to rebuy, just re-add. Move would be nice. Also like to add a preview option. 5: Would be cool Simulation mode would be cool
|
|
inherit
168679
0
Nov 18, 2012 17:03:07 GMT -8
Virgil Sovereign
Latet anguis in herba.
686
July 2011
syonidv
|
Post by Virgil Sovereign on Jul 28, 2014 7:12:59 GMT -8
1: as for number 1 I already have it set up so that it won't let you choose the no-image image (provided by the admin) but alert that the url is invalid and do nothing. 2: number 1 fixes this 3: Yeah changing size is on my list 4: Prob Rev 13 5: I got really confused on how to make the structure simple and yet feasible. I know that the polling could be a problem. However I couldn't think of a polling design at the time that would allow to 'restart' the group of movements. I will look into it. How about a simple poll spinning on a 10 ms interval and updating a common queue?
For example, create a Movement class:
ak.Movement = function( ... ) { this.animalID = ...; this.moves = []; this.currentMove = 0; this.timestamp = 0; ... }
representing the movement for one animal. Then populate a list of all movements:
ak.movements = [];
for( [every animal] ) if( [animal has movement] ) ak.movements.push( new ak.Movement( [animal ID], [moves sequence], ... ) );
Add an update function to the Movement prototype to run the next move in the motion sequence when the time is right. Also, you can have a "motion suspended" flag associated with each animal (discussed later) that comes into play here.
ak.Movement.prototype.update = function( time ) { if( [animal this.animalID is suspended] ) return;
if( time - this.timestamp > this.moves[this.currentMove].duration ) { this.timestamp = time; this.currentMove = (this.currentMove + 1) % this.moves.length; [animate move this.currentMove for this.animalID] } };
And then queuing of new moves for all animals can be handled by a single spinner:
setInterval( function() { var time = (new Date()).getTime(); $(ak.movements).each( function() { this.update( time ); } ); }, 10 );
This will also elegantly handle cases where a tab goes out of focus and/or if any animals' animation is suspended.6: Very true, I also thought about adding a preview box of how it's going to look before you submit your changes. 7: I will try to add an OR: in there to make it more clear. However I can't just save everyone's data willy nilly cause that would just crank up the key space. I do understand the concern, however aint nobody got time for dat. If neither are set, then it goes by the last height/width and usually defaults to what the admin says is max. What I meant was that instead of "Small", "Medium", "Large" presets being saved for each user, you would just save the last three (unique) sizes used. Hence the form would look something like:
Height: [ ] Width: [ ] Previous Sizes: height 75 width 120, height 120 height 300
Movement: [ v]
and clicking on any of the previous sizes would populate the Height and Width fields appropriately. Assuming you kept track of the three most recent sizes, the amount of data saved to the user key would be identical to the amount of data you're currently saving for the "Small", "Medium", and "Large" presets: just three pairs of numbers.8: I personally just implemented increasing happiness. However working on ideas on decreasing happiness. 9: The pet and wash work on my test field, probably just a glitch in your key data from rev13 or less 10: I didn't want to do it how I did, however I could not find another way to prevent execution of the next animation; I took a look at your code, and what I recommend is a simple animation handler that locks out new animations while old ones are running. For example, I would define a set of functions in the ak.anim namespace as follows:
// Select objects with AK ids ak.$ = function( id ) { return $($.map( id.split(','), function( s ) { return '#ak' + s; } ).join(',')); };
// Select holder objects ak.holderObject = function( holder ) { return $('.' + holder + 'holder'); };
// Animation handler ak.anim = { OPEN_CLOSE: { opacity: "toggle", height: "toggle" }, OPEN_CLOSE_TIME: 1000,
state: 'idle', duration: 0, queue: [],
init: function() { if( ak.anim.state != 'idle' ) return false;
ak.anim.state = 'queued'; ak.anim.duration = 0; ak.anim.queue = []; return true; },
add: function( target, params, duration ) { if( ak.anim.state != 'queued' ) return;
ak.anim.queue.push( { target: target, params: params, duration: duration } ); ak.anim.duration = Math.max( ak.anim.duration, duration ); },
execute: function() { if( ak.anim.state != 'queued' ) return;
ak.anim.state = 'running'; $(ak.anim.queue).each( function() { $(this.target).animate( this.params, this.duration ); } );
setTimeout( function() { ak.anim.state = 'idle'; }, ak.anim.duration ); },
oneShot: function( target, params, duration ) { if( ak.anim.init() ) { ak.anim.add( target, params, duration ); ak.anim.execute(); } },
toggleVisible : function( target ) { ak.anim.add( target, ak.anim.OPEN_CLOSE, ak.anim.OPEN_CLOSE_TIME ); },
hide : function( target ) { if( target.is( ":visible" ) ) ak.anim.toggleVisible( target ); } };
This can be used to handle animations in one of two ways:
- for a single animation, by calling ak.anim.oneShot( ... ) with the target and animation parameters
- for multiple animations running simultaneously, by:
- invoking ak.anim.init() and checking its return value
- if the return value is false, one or more animations are still in progress; do nothing
- if the return value is true, using ak.anim.add( ... ) to add all animations that will run concurrently
- invoking ak.anim.execute() to execute the animation(s)
As an example, consider the code you use to toggle the active tab, which is found in the three functions:
function akanimatehide() { if($("#akreleaseconfirm").is(":visible")){ $( "#akreleaseconfirm" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { }); } if($("#akbuyform").is(":visible")){ $( "#akbuyform" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });} if($("#akinventory").is(":visible")){ $( "#akinventory" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });} if($("#akbuyconfirm").is(":visible")){ $( "#akbuyconfirm" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });} if($("#aktoyform").is(":visible")){ $( "#aktoyform" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });} if($("#aktoyinventory").is(":visible")){ $( "#aktoyinventory" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });} if($("#akplayview").is(":visible")){ $( "#akplayview" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });} if($("#aktoybuyconfirm").is(":visible")){ $( "#aktoybuyconfirm" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });}
}
function akhideholders(current) { akanimatehide(); if(current != 'ledger') if($(".ledgerholder").is(":visible")){$( ".ledgerholder" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() {})} if(current != 'play') if($(".playholder").is(":visible")){$( ".playholder" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() {})} if(current != 'background') if($(".backgroundholder").is(":visible")){$( ".backgroundholder" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() {})} }
$( document ).ready(function() { //Stop Spam Click $('img').click(function () { if ($('div:animated').length) { throw new Error('Animation Incomplete') //allows image animation not div }}); //GUIDE BUTTONS////////////////////////////////////////////////// //Open Ledger
$( "#akledger" ).click(function() { akhideholders('ledger'); if($(".keeperholder").is(":visible") || $(".ledgerholder").is(":visible")){ $( ".keeperholder" ).animate({ opacity: "toggle", height: "toggle" }, 1000, function() { //animation complete }) $( ".ledgerholder" ).animate({ opacity: "toggle", height: "toggle" }, 1000, function() { })}else{$( ".ledgerholder" ).animate({opacity: "toggle", height: "toggle" }, 1000, function() { })} ;}) $( "#akplay" ).click(function() { akhideholders('play'); if($(".keeperholder").is(":visible") || $(".playholder").is(":visible")){ $( ".keeperholder" ).animate({ opacity: "toggle", height: "toggle" }, 1000, function() { }) $( ".playholder" ).animate({ opacity: "toggle", height: "toggle" }, 1000, function() { })}else{$( ".playholder" ).animate({opacity: "toggle", height: "toggle" }, 1000, function() { })} ;}) $( "#akbackgrounds" ).click(function() { akhideholders('background'); if($(".keeperholder").is(":visible") || $(".backgroundholder").is(":visible")){ $( ".keeperholder" ).animate({ opacity: "toggle", height: "toggle" }, 1000, function() { }) $( ".backgroundholder" ).animate({ opacity: "toggle", height: "toggle" }, 1000, function() { })}else{$( ".backgroundholder" ).animate({opacity: "toggle", height: "toggle" }, 1000, function() { })} ;})
... })
This would alternatively be handled by the animation handler as:
ak.HOLDERS = ['keeper','ledger','play','background'];
ak.INTERNAL_FORMS = ['releaseconfirm','buyform','inventory','buyconfirm','toyform', 'toyinventory','playview','toybuyconfirm'];
ak.hideInternalForms = function() { $(ak.INTERNAL_FORMS).each( function() { ak.anim.hide( ak.$(this) ); } ); };
ak.setActiveHolder = function( holder ) { if( !ak.anim.init() ) return;
ak.hideInternalForms(); $(ak.HOLDERS).each( function() { var o = ak.holderObject( this ); if( o.is( ":visible" ) != (this == holder) ) ak.anim.toggleVisible( o ); } );
ak.anim.execute(); };
$(ak.HOLDERS).each( function() { var holder = this; ak.$(holder).click( function() { ak.setActiveHolder( ak.holderObject( holder ).is( ":visible" ) ? 'keeper' : holder ); } ); } );
A one-shot animation such as:
var hidenow = 800; $( "#akviewtoy, #aktoyinventory" ).animate({ opacity: "toggle", height: "toggle" }, hidenow, function() { });
would be alternatively handled with
ak.anim.oneShot( ak.$("viewtoy,toyinventory"), ak.anim.OPEN_CLOSE, ak.anim.OPEN_CLOSE_TIME );
Having an animation handler will also allow you to collect parameters (such as the animation effects and durations) in a single place. 11:Planned on it 1: A fast moving animal wouldn't be readable then. I suggest that for a fast-moving animal, hovering the cursor over the animal would suspend the animation. The pseudocode above provides a suggestion of how to accomplish this.2: Would take referencing height,width of image and comparing to current position and factoring the play field height and width and displaying it left or right and counteracting the length of the popup bubble via the size of the description and factoring in the height whether it should be displayed higher. Simplicity is better for me. Simplicity is good. 3: My positoning is a little off, will look into 4: you don't have to rebuy, just re-add. Move would be nice. Also like to add a preview option. 5: Would be cool Simulation mode would be cool Comments inline in blue.
|
|
inherit
201984
0
Sept 11, 2023 1:23:07 GMT -8
P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓
Using My Talents Elsewhere
3,314
November 2013
pastuleo23
|
Post by P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓ on Jul 28, 2014 21:14:44 GMT -8
1: as for number 1 I already have it set up so that it won't let you choose the no-image image (provided by the admin) but alert that the url is invalid and do nothing. 2: number 1 fixes this 3: Yeah changing size is on my list 4: Prob Rev 13 5: I got really confused on how to make the structure simple and yet feasible. I know that the polling could be a problem. However I couldn't think of a polling design at the time that would allow to 'restart' the group of movements. I will look into it. How about a simple poll spinning on a 10 ms interval and updating a common queue?
For example, create a Movement class:
ak.Movement = function( ... ) { this.animalID = ...; this.moves = []; this.currentMove = 0; this.timestamp = 0; ... }
representing the movement for one animal. Then populate a list of all movements:
ak.movements = [];
for( [every animal] ) if( [animal has movement] ) ak.movements.push( new ak.Movement( [animal ID], [moves sequence], ... ) );
Add an update function to the Movement prototype to run the next move in the motion sequence when the time is right. Also, you can have a "motion suspended" flag associated with each animal (discussed later) that comes into play here.
ak.Movement.prototype.update = function( time ) { if( [animal this.animalID is suspended] ) return;
if( time - this.timestamp > this.moves[this.currentMove].duration ) { this.timestamp = time; this.currentMove = (this.currentMove + 1) % this.moves.length; [animate move this.currentMove for this.animalID] } };
And then queuing of new moves for all animals can be handled by a single spinner:
setInterval( function() { var time = (new Date()).getTime(); $(ak.movements).each( function() { this.update( time ); } ); }, 10 );
This will also elegantly handle cases where a tab goes out of focus and/or if any animals' animation is suspended.6: Very true, I also thought about adding a preview box of how it's going to look before you submit your changes. 7: I will try to add an OR: in there to make it more clear. However I can't just save everyone's data willy nilly cause that would just crank up the key space. I do understand the concern, however aint nobody got time for dat. If neither are set, then it goes by the last height/width and usually defaults to what the admin says is max. What I meant was that instead of "Small", "Medium", "Large" presets being saved for each user, you would just save the last three (unique) sizes used. Hence the form would look something like:
Height: [ ] Width: [ ] Previous Sizes: height 75 width 120, height 120 height 300
Movement: [ v]
and clicking on any of the previous sizes would populate the Height and Width fields appropriately. Assuming you kept track of the three most recent sizes, the amount of data saved to the user key would be identical to the amount of data you're currently saving for the "Small", "Medium", and "Large" presets: just three pairs of numbers.8: I personally just implemented increasing happiness. However working on ideas on decreasing happiness. 9: The pet and wash work on my test field, probably just a glitch in your key data from rev13 or less 10: I didn't want to do it how I did, however I could not find another way to prevent execution of the next animation; I took a look at your code, and what I recommend is a simple animation handler that locks out new animations while old ones are running. For example, I would define a set of functions in the ak.anim namespace as follows:
// Select objects with AK ids ak.$ = function( id ) { return $($.map( id.split(','), function( s ) { return '#ak' + s; } ).join(',')); };
// Select holder objects ak.holderObject = function( holder ) { return $('.' + holder + 'holder'); };
// Animation handler ak.anim = { OPEN_CLOSE: { opacity: "toggle", height: "toggle" }, OPEN_CLOSE_TIME: 1000,
state: 'idle', duration: 0, queue: [],
init: function() { if( ak.anim.state != 'idle' ) return false;
ak.anim.state = 'queued'; ak.anim.duration = 0; ak.anim.queue = []; return true; },
add: function( target, params, duration ) { if( ak.anim.state != 'queued' ) return;
ak.anim.queue.push( { target: target, params: params, duration: duration } ); ak.anim.duration = Math.max( ak.anim.duration, duration ); },
execute: function() { if( ak.anim.state != 'queued' ) return;
ak.anim.state = 'running'; $(ak.anim.queue).each( function() { $(this.target).animate( this.params, this.duration ); } );
setTimeout( function() { ak.anim.state = 'idle'; }, ak.anim.duration ); },
oneShot: function( target, params, duration ) { if( ak.anim.init() ) { ak.anim.add( target, params, duration ); ak.anim.execute(); } },
toggleVisible : function( target ) { ak.anim.add( target, ak.anim.OPEN_CLOSE, ak.anim.OPEN_CLOSE_TIME ); },
hide : function( target ) { if( target.is( ":visible" ) ) ak.anim.toggleVisible( target ); } };
This can be used to handle animations in one of two ways:
- for a single animation, by calling ak.anim.oneShot( ... ) with the target and animation parameters
- for multiple animations running simultaneously, by:
- invoking ak.anim.init() and checking its return value
- if the return value is false, one or more animations are still in progress; do nothing
- if the return value is true, using ak.anim.add( ... ) to add all animations that will run concurrently
- invoking ak.anim.execute() to execute the animation(s)
As an example, consider the code you use to toggle the active tab, which is found in the three functions:
function akanimatehide() { if($("#akreleaseconfirm").is(":visible")){ $( "#akreleaseconfirm" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { }); } if($("#akbuyform").is(":visible")){ $( "#akbuyform" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });} if($("#akinventory").is(":visible")){ $( "#akinventory" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });} if($("#akbuyconfirm").is(":visible")){ $( "#akbuyconfirm" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });} if($("#aktoyform").is(":visible")){ $( "#aktoyform" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });} if($("#aktoyinventory").is(":visible")){ $( "#aktoyinventory" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });} if($("#akplayview").is(":visible")){ $( "#akplayview" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });} if($("#aktoybuyconfirm").is(":visible")){ $( "#aktoybuyconfirm" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() { });}
}
function akhideholders(current) { akanimatehide(); if(current != 'ledger') if($(".ledgerholder").is(":visible")){$( ".ledgerholder" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() {})} if(current != 'play') if($(".playholder").is(":visible")){$( ".playholder" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() {})} if(current != 'background') if($(".backgroundholder").is(":visible")){$( ".backgroundholder" ).animate({ opacity: "toggle", height: "toggle" }, 800, function() {})} }
$( document ).ready(function() { //Stop Spam Click $('img').click(function () { if ($('div:animated').length) { throw new Error('Animation Incomplete') //allows image animation not div }}); //GUIDE BUTTONS////////////////////////////////////////////////// //Open Ledger
$( "#akledger" ).click(function() { akhideholders('ledger'); if($(".keeperholder").is(":visible") || $(".ledgerholder").is(":visible")){ $( ".keeperholder" ).animate({ opacity: "toggle", height: "toggle" }, 1000, function() { //animation complete }) $( ".ledgerholder" ).animate({ opacity: "toggle", height: "toggle" }, 1000, function() { })}else{$( ".ledgerholder" ).animate({opacity: "toggle", height: "toggle" }, 1000, function() { })} ;}) $( "#akplay" ).click(function() { akhideholders('play'); if($(".keeperholder").is(":visible") || $(".playholder").is(":visible")){ $( ".keeperholder" ).animate({ opacity: "toggle", height: "toggle" }, 1000, function() { }) $( ".playholder" ).animate({ opacity: "toggle", height: "toggle" }, 1000, function() { })}else{$( ".playholder" ).animate({opacity: "toggle", height: "toggle" }, 1000, function() { })} ;}) $( "#akbackgrounds" ).click(function() { akhideholders('background'); if($(".keeperholder").is(":visible") || $(".backgroundholder").is(":visible")){ $( ".keeperholder" ).animate({ opacity: "toggle", height: "toggle" }, 1000, function() { }) $( ".backgroundholder" ).animate({ opacity: "toggle", height: "toggle" }, 1000, function() { })}else{$( ".backgroundholder" ).animate({opacity: "toggle", height: "toggle" }, 1000, function() { })} ;})
... })
This would alternatively be handled by the animation handler as:
ak.HOLDERS = ['keeper','ledger','play','background'];
ak.INTERNAL_FORMS = ['releaseconfirm','buyform','inventory','buyconfirm','toyform', 'toyinventory','playview','toybuyconfirm'];
ak.hideInternalForms = function() { $(ak.INTERNAL_FORMS).each( function() { ak.anim.hide( ak.$(this) ); } ); };
ak.setActiveHolder = function( holder ) { if( !ak.anim.init() ) return;
ak.hideInternalForms(); $(ak.HOLDERS).each( function() { var o = ak.holderObject( this ); if( o.is( ":visible" ) != (this == holder) ) ak.anim.toggleVisible( o ); } );
ak.anim.execute(); };
$(ak.HOLDERS).each( function() { var holder = this; ak.$(holder).click( function() { ak.setActiveHolder( ak.holderObject( holder ).is( ":visible" ) ? 'keeper' : holder ); } ); } );
A one-shot animation such as:
var hidenow = 800; $( "#akviewtoy, #aktoyinventory" ).animate({ opacity: "toggle", height: "toggle" }, hidenow, function() { });
would be alternatively handled with
ak.anim.oneShot( ak.$("viewtoy,toyinventory"), ak.anim.OPEN_CLOSE, ak.anim.OPEN_CLOSE_TIME );
Having an animation handler will also allow you to collect parameters (such as the animation effects and durations) in a single place. 11:Planned on it 1: A fast moving animal wouldn't be readable then. I suggest that for a fast-moving animal, hovering the cursor over the animal would suspend the animation. The pseudocode above provides a suggestion of how to accomplish this.2: Would take referencing height,width of image and comparing to current position and factoring the play field height and width and displaying it left or right and counteracting the length of the popup bubble via the size of the description and factoring in the height whether it should be displayed higher. Simplicity is better for me. Simplicity is good. 3: My positoning is a little off, will look into 4: you don't have to rebuy, just re-add. Move would be nice. Also like to add a preview option. 5: Would be cool Simulation mode would be cool Comments inline in blue. Namespaces still confuse the crap outta me.
|
|
inherit
168679
0
Nov 18, 2012 17:03:07 GMT -8
Virgil Sovereign
Latet anguis in herba.
686
July 2011
syonidv
|
Post by Virgil Sovereign on Jul 29, 2014 4:19:33 GMT -8
All a namespace is is a way to prevent the name of your functions, global variables, etc. from conflicting with everyone else's. You're actually using a form of namespace by prefixing your functions and global variables with ak. In JS, the more customary method is to create an object that represents your namespace and assigning all globals, functions, classes, etc. to fields in this object. For example, var akbaz = 0;
function akfoo() { akbaz++; ... }
function akbar() { akfoo(); ... }
would instead look like: var ak = {};
ak.baz = 0; ak.foo = function() { ak.baz++; ... };
ak.bar = function() { ak.foo(); ... };
There are several advantages to using this latter method which I won't get into here. If you prefer to use prefixes, that's fine too. And if you wanted to use the code I provided, the conversion to prefixes is simple. For example, var ak_HOLDERS = ['keeper','ledger','play','background'];
var ak_INTERNAL_FORMS = ['releaseconfirm','buyform','inventory','buyconfirm','toyform', 'toyinventory','playview','toybuyconfirm'];
function akHideInternalForms() { $(ak_INTERNAL_FORMS).each( function() { akAnimHide( ak$(this) ); } ); };
function akSetActiveHolder( holder ) { if( !akAnimInit() ) return;
akHideInternalForms(); $(ak_HOLDERS).each( function() { var o = akHolderObject( this ); if( o.is( ":visible" ) != (this == holder) ) akAnimToggleVisible( o ); } );
akAnimExecute(); };
$(ak_HOLDERS).each( function() { var holder = this; ak$(holder).click( function() { akSetActiveHolder( akHolderObject( holder ).is( ":visible" ) ? 'keeper' : holder ); } ); } ); and so on.
|
|
inherit
201984
0
Sept 11, 2023 1:23:07 GMT -8
P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓
Using My Talents Elsewhere
3,314
November 2013
pastuleo23
|
Post by P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓ on Jul 30, 2014 22:52:21 GMT -8
All a namespace is is a way to prevent the name of your functions, global variables, etc. from conflicting with everyone else's. You're actually using a form of namespace by prefixing your functions and global variables with ak. In JS, the more customary method is to create an object that represents your namespace and assigning all globals, functions, classes, etc. to fields in this object. For example, var akbaz = 0;
function akfoo() { akbaz++; ... }
function akbar() { akfoo(); ... }
would instead look like: var ak = {};
ak.baz = 0; ak.foo = function() { ak.baz++; ... };
ak.bar = function() { ak.foo(); ... };
There are several advantages to using this latter method which I won't get into here. If you prefer to use prefixes, that's fine too. And if you wanted to use the code I provided, the conversion to prefixes is simple. For example, var ak_HOLDERS = ['keeper','ledger','play','background'];
var ak_INTERNAL_FORMS = ['releaseconfirm','buyform','inventory','buyconfirm','toyform', 'toyinventory','playview','toybuyconfirm'];
function akHideInternalForms() { $(ak_INTERNAL_FORMS).each( function() { akAnimHide( ak$(this) ); } ); };
function akSetActiveHolder( holder ) { if( !akAnimInit() ) return;
akHideInternalForms(); $(ak_HOLDERS).each( function() { var o = akHolderObject( this ); if( o.is( ":visible" ) != (this == holder) ) akAnimToggleVisible( o ); } );
akAnimExecute(); };
$(ak_HOLDERS).each( function() { var holder = this; ak$(holder).click( function() { akSetActiveHolder( akHolderObject( holder ).is( ":visible" ) ? 'keeper' : holder ); } ); } ); and so on. Thanks for explaining it. I think I better grasp the concept now.
|
|
inherit
201984
0
Sept 11, 2023 1:23:07 GMT -8
P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓
Using My Talents Elsewhere
3,314
November 2013
pastuleo23
|
Post by P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓ on Jul 31, 2014 12:47:27 GMT -8
Man, I see the ingenious of that modulus
|
|
inherit
201984
0
Sept 11, 2023 1:23:07 GMT -8
P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓
Using My Talents Elsewhere
3,314
November 2013
pastuleo23
|
Post by P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓ on Aug 3, 2014 16:42:06 GMT -8
All a namespace is is a way to prevent the name of your functions, global variables, etc. from conflicting with everyone else's. You're actually using a form of namespace by prefixing your functions and global variables with ak. In JS, the more customary method is to create an object that represents your namespace and assigning all globals, functions, classes, etc. to fields in this object. For example, var akbaz = 0;
function akfoo() { akbaz++; ... }
function akbar() { akfoo(); ... }
would instead look like: var ak = {};
ak.baz = 0; ak.foo = function() { ak.baz++; ... };
ak.bar = function() { ak.foo(); ... };
There are several advantages to using this latter method which I won't get into here. If you prefer to use prefixes, that's fine too. And if you wanted to use the code I provided, the conversion to prefixes is simple. For example, var ak_HOLDERS = ['keeper','ledger','play','background'];
var ak_INTERNAL_FORMS = ['releaseconfirm','buyform','inventory','buyconfirm','toyform', 'toyinventory','playview','toybuyconfirm'];
function akHideInternalForms() { $(ak_INTERNAL_FORMS).each( function() { akAnimHide( ak$(this) ); } ); };
function akSetActiveHolder( holder ) { if( !akAnimInit() ) return;
akHideInternalForms(); $(ak_HOLDERS).each( function() { var o = akHolderObject( this ); if( o.is( ":visible" ) != (this == holder) ) akAnimToggleVisible( o ); } );
akAnimExecute(); };
$(ak_HOLDERS).each( function() { var holder = this; ak$(holder).click( function() { akSetActiveHolder( akHolderObject( holder ).is( ":visible" ) ? 'keeper' : holder ); } ); } ); and so on. Thanks for explaining it. I think I better grasp the concept now. I modified the code snippets your provided but kept the basic structure. It is definitely well-developed and I give you props. Now I have more control over my animations and movements. It however was ten times harder to set up than what I was doing.
|
|
inherit
212652
0
Dec 22, 2016 6:08:00 GMT -8
Concept
145
August 2014
kota1
|
Post by Concept on Aug 11, 2014 13:24:06 GMT -8
whats the tab URL?
|
|
inherit
201984
0
Sept 11, 2023 1:23:07 GMT -8
P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓
Using My Talents Elsewhere
3,314
November 2013
pastuleo23
|
Post by P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓ on Aug 15, 2014 0:01:27 GMT -8
|
|
inherit
201984
0
Sept 11, 2023 1:23:07 GMT -8
P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓
Using My Talents Elsewhere
3,314
November 2013
pastuleo23
|
Post by P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓ on Aug 23, 2014 23:08:47 GMT -8
|
|
inherit
(?)?
188910
0
Jan 26, 2013 13:30:48 GMT -8
♥ ℒʊ√ ♥
Clouds float into my life no longer to carry rain or usher storm but to add color to my sunset sky.
10,458
January 2013
luv
|
Post by ♥ ℒʊ√ ♥ on Aug 23, 2014 23:13:24 GMT -8
Congrats, on the first release, P̌̓aͧś̀t̀u͒le͆o͂2̀3̃̓.
The work, the detail, the time and effort you put into this ~ along with trying to accommodate everyone's input, is amazing.
Well done!
|
|
Former Member
inherit
guest@proboards.com
177794
0
Apr 19, 2024 1:32:36 GMT -8
Former Member
0
January 1970
Former Member
|
Post by Former Member on Aug 24, 2014 11:55:41 GMT -8
Im testing it and it looks awesome!
Just a couple suggestions. Maybe change the text images to just text where you can alter the font style and size? It would save time so the admins wont need to make all those image files to match their forums style.
Also once you go into the ledger its hard to get back to the area with the pet. I found I had to keep clicking the tab. Maybe a back button or a "Return to" button? ^^
I also had to snoop around a bit to find the area where you purchase the animal. Since that will be the first thing the players look for maybe a direct button to the shop?
Also would there be a way to disable the image button so players cant change the default background?
Just ideas of course! I really like the playability factor this has!
|
|