var targetscript : Diamond;
var red : Color;
var orange : Color;
function Start () {
gameObject.camera.backgroundColor = red;
}
function Update () {
if (targetscript.score > 4) {
gameObject.camera.backgroundColor = Color.Lerp(red, orange, Time.time);
}
}
So right now, if the score is larger than 4 then it would change the camera background color to orange with lerp. But its too quick. I read on the internet that Time.time is 1 second. What is the alternative way but for 2 or 3 seconds? I tried this : http://answers.unity3d.com/questions/328891/controlling-duration-of-colorlerp-in-seconds.html I tried the code for the voted answer but it didn't work. It still lerps through quickly. Does anyone have any ideas? Thanks
Time.time gives you the time in seconds since the start of the game. What you want is Time.deltaTime which is the time difference between each frames.
var targetscript : Diamond;
var red : Color;
var orange : Color;
var t : float = 0;
var duration : float = 3.0; //however long you want it to be
function Start () {
gameObject.camera.backgroundColor = red;
}
function Update () {
if (targetscript.score > 4) {
gameObject.camera.backgroundColor = Color.Lerp(red, orange, t);
t += Time.deltaTime/duration;
}
}
Color.Lerp(Color a, Color b, float t), so:
-> t = 0, the Color result is a
-> t = 0.5, the Color result is half a and half b
-> t = 1.0, the Color result is b
Based on that definition, when Time.time return value >= 1.0 the Lerp will be completed. That's why your code finish in 1 seconds.
so, you can change the update function like this:
var duration : float = 3.0; //however long you want it to be
function Update ()
{
if (targetscript.score > 4)
{
gameObject.camera.backgroundColor = Color.Lerp(red, orange, Time.time / duration);
}
}
This will make the Lerp completes exactly as the duration. because Time.time / duration >= 1 when Time.time >= duration.
Related
I have a min and max parameter which each require a double.
min: 0,
max: _duration!.inMilliseconds
These parameters are then converted to strings for use as dynamic text on top of the thumb ball of a slider.
But for the max value I'd like to use the actual duration instead;
IE: 1:34:30 instead of 94,500.
The final product required is a String.
So how do I get the Duration to a string while preserving the Duration formatting?
Keep in mind it is passed initially as a double.
Here's the full class for the thumb ball;
class CustomSliderThumbCircle extends SliderComponentShape {
final double thumbRadius;
final int min;
final int max;
const CustomSliderThumbCircle({
required this.thumbRadius,
this.min = 0,
this.max = 10,
});
#override
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
return Size.fromRadius(thumbRadius);
}
#override
void paint(
PaintingContext context,
Offset center, {
Animation<double>? activationAnimation,
Animation<double>? enableAnimation,
bool? isDiscrete,
TextPainter? labelPainter,
RenderBox? parentBox,
SliderThemeData? sliderTheme,
TextDirection? textDirection,
double? value,
double? textScaleFactor,
Size? sizeWithOverflow,
}) {
final Canvas canvas = context.canvas;
final paint = Paint()
..color = Colors.white //Thumb Background Color
..style = PaintingStyle.fill;
TextSpan span = new TextSpan(
style: new TextStyle(
fontSize: thumbRadius,
//fontWeight: FontWeight.w700,
color: Colors.white, //Text Color of Value on Thumb
),
text: getValue(value!),
);
TextPainter tp = new TextPainter(
text: span,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr);
tp.layout();
Offset textCenter =
Offset(center.dx - (tp.width / 2), center.dy - (tp.height / 2));
final rect = Rect.fromCircle(center: center, radius: thumbRadius);
final rrect = RRect.fromRectAndRadius(
Rect.fromPoints(
Offset(rect.left - 10, rect.top),
Offset(rect.right + 10, rect.bottom),
),
Radius.elliptical(20, 100),
);
final fillPaint = Paint()
..color = sliderTheme!.activeTrackColor!
..style = PaintingStyle.fill;
final borderPaint = Paint()
..color = Colors.black
..strokeWidth = 2.8
..style = PaintingStyle.stroke;
canvas.drawRRect(rrect, fillPaint);
canvas.drawRRect(rrect, borderPaint);
tp.paint(canvas, textCenter);
}
String getValue(double value) {
return (min + (max - min) * value).round().toString();
}
}
If CustomSliderThumbCircle is your own class, I would change it to take a callback function to format the value to a String (falling back to just .toString() if no callback is specified), something like:
class CustomSliderThumbCircle extends SliderComponentShape {
final String Function(int value)? formatValue;
...
const CustomSliderThumbCircle({
required this.thumbRadius,
this.min = 0,
this.max = 10,
this.formatValue,
});
String getValue(double value) {
var clamped = (min + (max - min) * value).round();
return (formatValue == null) ? clamped.toString() : formatValue!(clamped);
}
}
and then your caller could pass a callback:
CustomSliderThumbCircle(
thumbRadius: ...,
...,
formatValue: (value) => Duration(milliseconds: value).toString(),
)
This also would allow you to use a function that formats Durations as, say, 1m34.5s instead of as 0:01:34.500000. I generally dislike representing durations with colons because it can be ambiguous if fractional seconds are omitted. For example, using a different function to format Durations:
CustomSliderThumbCircle(
thumbRadius: ...,
...,
formatValue: (value) => prettyDuration(Duration(milliseconds: value)),
)
If CustomSliderThumbCircle is not under your control, then you could extend it with your own class that overrides getValue.
I doubt this is better than jamesdlin's solution but I don't know how to format it the way I'd like using the call back. Plus I realised I only need seconds and milliseconds as the audio is limited to 60 seconds anyway. So here's what I did;
String getValue(double value) {
double seconds = value * (max/1000);
String secstring = secs.truncate().toString();
var milliseconds = value * (max.remainder(1000));
String millistring = milliseconds.truncate().toString();
String stringDuration = secstring + ':' + millistring;
return stringDuration ;
}
I was trying to maintain the object size while zooming, i tried to get inspired by this answer in which the guy who wrote it didn't solve the controls issue in such as case, as a consequence you can see them not sticking to the object while zooming as in this screenshot.
But i came with this solution to maintain the object position and controls by updating its left and top after calculating them based on the inverted viewportTransform by calculating a new fabric.Point using the fabric.util.transformPoint function
fabric.Object.prototype.transform = function(ctx) {
const obj = this;
const {
ignoreZoom,
group,
canvas,
left,
top
} = obj;
const {
contextTop,
viewportTransform,
getZoom,
requestRenderAll,
} = canvas;
var needFullTransform = (group && !group._transformDone) || (group && canvas && ctx === contextTop);
if (ignoreZoom) {
const oldP = new fabric.Point(left, top);
const newP = fabric.util.transformPoint(oldP, fabric.util.invertTransform(viewportTransform));
var zoom = 1 / getZoom();
/* // here i tried to refresh the whole canvas with requestRenderAll()
this.set({
left: newP.x,
top: newP.y,
scaleX: zoom,
scaleY: zoom,
});
this.setCoords();
requestRenderAll();
*/
// but here i try refresh the object only which is better i think
this.left = newP.x;
this.top = newP.y;
this.scaleX = zoom;
this.scaleY = zoom;
this.drawObject(ctx);
}
var m = this.calcTransformMatrix(!needFullTransform);
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
}
I have made this codesandbox as a demo for my code. As you can see in this screenshot, controls stick around the object but the whole of them doesn't maintain their position relatively to the background and sometimes they disappear completely.
I need the object to keep its position relatively to the background.
How to make it better ?
// EDIT
I tried to understand better what happens while zooming, i found the fabric.Canvas.zoomToPoint() which is used for zooming (as in their tutorial)
zoomToPoint: function (point, value) {
// TODO: just change the scale, preserve other transformations
var before = point, vpt = this.viewportTransform.slice(0);
point = transformPoint(point, invertTransform(this.viewportTransform));
vpt[0] = value;
vpt[3] = value;
var after = transformPoint(point, vpt);
vpt[4] += before.x - after.x;
vpt[5] += before.y - after.y;
return this.setViewportTransform(vpt);
},
i guess the best way to fix the object position relatively to the background will be to apply the inverse transformation of the one applied to the canvas for the zoom to the object.
So i wrote this function
function getNewVpt(point, value) {
var before = point,
vpt = canvas.viewportTransform.slice(0);
point = fabric.util.transformPoint(point, fabric.util.invertTransform(canvas.viewportTransform));
vpt[0] = value;
vpt[3] = value;
var after = fabric.util.transformPoint(point, vpt);
vpt[4] += before.x - after.x;
vpt[5] += before.y - after.y;
return vpt;
}
and i used it to rewrite the fabric.Object.prototype.transform
fabric.Object.prototype.transform = function (ctx) {
const obj = this;
const { ignoreZoom, group, canvas: objCanvas, left, top } = obj;
const {
contextTop,
viewportTransform,
} = objCanvas;
var needFullTransform =
(group && !group._transformDone) ||
(group && objCanvas && ctx === contextTop);
if (ignoreZoom && zoomingIsOn) {
zoomingIsOn = false;
var zoom = 1 / objCanvas.getZoom();
const oldP = new fabric.Point(left, top);
console.log('transform : oldP : ', oldP);
const newVpt = getNewVpt(oldP, zoom)
const newP = fabric.util.transformPoint(oldP, newVpt);
console.log('transform : newP : ', newP);
// here i tried to refresh the whole canvas with requestRenderAll()
this.set({
left: newP.x,
top: newP.y,
scaleX: zoom,
scaleY: zoom
});
this.setCoords();
console.log('transform : CALLING objCanvas.requestRenderAll() ');
objCanvas.requestRenderAll();
// but here i try refresh the object only which is better i think
// this.left = newP.x;
// this.top = newP.y;
// this.scaleX = zoom;
// this.scaleY = zoom;
// this.drawObject(ctx);
}
var m = this.calcTransformMatrix(!needFullTransform);
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
};
And here i forked this new codesandbox for this second solution , the result seems to be better than the former solution but it still not perfect. What i may still be doing wrong ?!
// EDIT 2
I tried to pass objCanvas.getZoom() instead of zoom as second parameter to the getNewVpt() function. It seems there is some more improovement but still not perfect again
// Edit 3
In This codesandbox probably i got the best result i could get using another function which returns directly the new point:
function getNewPt(point, value) {
// TODO: just change the scale, preserve other transformations
var vpt = canvas.viewportTransform.slice(0);
point = fabric.util.transformPoint(point, fabric.util.invertTransform(canvas.viewportTransform));
vpt[0] = value;
vpt[3] = value;
return fabric.util.transformPoint(point, vpt);;
}
I still wish anybody who can tell me if there is a way to improove it more. As you can see the triangle returns back to its initial position after zooming/ dezooming and getting back to the same initial zoom value which is good but between those initial and final states , it still seems not to be in the right spot..
You just have to call zoomToPoint where it zooms and the objects will keep their position and scale relative to the background.
Try the following
canvas.on('mouse:wheel', function(opt) {
// console.log(opt.e.deltaY)
let zoomLevel = canvas.getZoom();
// console.log('zoom Level: ', (zoomLevel * 100).toFixed(0), '%');
zoomLevel += opt.e.deltaY * -0.01;
// Restrict scale
zoomLevel = Math.min(Math.max(.125, zoomLevel), 20);
canvas.zoomToPoint(
new fabric.Point(opt.e.offsetX, opt.e.offsetY),
zoomLevel,
);
canvas.renderAll();
})
I made player script with touch location and Flip code to flip player wich direction is run i made like this but just flip from 0. If is on x = -5 and i touch to go in x = 2 player dont flip but when is on x = 0 is flip. Can someone tell me how to do this and i like to make with flor but my player move only on one flor in yAxis direction it save but when i remove yAxis it move all around i like to move like this gameGame
if (gameObject.transform.position.x > 0 && faceRight)
{
Flip();
}
else if (gameObject.transform.position.x < 0 && !faceRight)
{
Flip();
}
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour
{
private bool flag = false;
private Vector3 endPoint;
public float duration;
private float yAxis;
private bool Run = false;
private Animator anim;
private bool faceRight = true;
void Start()
{
anim = GetComponent<Animator>();
//save the y axis value of gameobject
yAxis = gameObject.transform.position.y;
}
// Update is called once per frame
void Update()
{
//check if the screen is touched / clicked
if ((Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began) || (Input.GetMouseButtonDown(0)))
{
//declare a variable of RaycastHit struct
RaycastHit hit;
//Create a Ray on the tapped / clicked position
Ray ray;
//for unity editor
#if UNITY_EDITOR
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//for touch device
#elif (UNITY_ANDROID || UNITY_IPHONE || UNITY_WP8)
ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
#endif
//Check if the ray hits any collider
if (Physics.Raycast(ray, out hit))
{
//set a flag to indicate to move the gameobject
flag = true;
//save the click / tap position
endPoint = hit.point;
//as we do not want to change the y axis value based on touch position, reset it to original y axis value
endPoint.y = yAxis;
Debug.Log(endPoint);
}
}
//check if the flag for movement is true and the current gameobject position is not same as the clicked / tapped position
if (flag && !Mathf.Approximately(gameObject.transform.position.magnitude, endPoint.magnitude))
{ //&& !(V3Equal(transform.position, endPoint))){
//move the gameobject to the desired position
gameObject.transform.position = Vector3.Lerp(gameObject.transform.position, endPoint, 1 / (duration * (Vector3.Distance(gameObject.transform.position, endPoint))));
Run = true;
anim.SetBool("Run", Run);
if (gameObject.transform.position.x > 0 && !faceRight)
{
Flip();
}
else if (gameObject.transform.position.x < 0 && faceRight)
{
Flip();
}
}
//set the movement indicator flag to false if the endPoint and current gameobject position are equal
else if (flag && Mathf.Approximately(gameObject.transform.position.magnitude, endPoint.magnitude))
{
flag = false;
Run = false;
anim.SetBool("Run", Run);
Debug.Log("I am here");
}
}
void Flip()
{
faceRight = !faceRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
Well my anwer will be diffrent from your code but if you want to flip character when you running left (i am assuming the default as right), you can simply check
if character's velocity > 0 then scale 1 and if character's velocity < 0 then scale -1
That will face the character to the rotation you go and this will be easy than the original code, but if you want to achieve something else please let me know so i can correct my answer on your needs :)
Flipping the character seems to be a thing that Animator should handle. I saw that you're already using Animator, so you should make something like:
anim.SetInteger("direction", 1)
or even:
anim.SetFloat("position", transform.position.x)
and configure the animator to act accordingly, creating the animation states with the character facing left and right (with the gameObject's transform scale.x 1 and -1 or rotation.y 0 and 180) and the transitions to respond to the events you decided to watch.
I am working on GA for a project. I am trying to solve Travelling Salesman Problem using GA. I used array[] to store data, I think Arrays are much faster than List. But for any reason it takes too much time. e.g. With MaxPopulation = 100000, StartPopulation=1000 the program lasts to complete about 1 min. I want to know if this is a problem. If it is, how can I fix this?
A code part from my implementation:
public void StartAsync()
{
Task.Run(() =>
{
CreatePopulation();
currentPopSize = startPopNumber;
while (currentPopSize < maxPopNumber)
{
Tour[] elits = ElitChromosoms();
for (int i = 0; i < maxCrossingOver; i++)
{
if (currentPopSize >= maxPopNumber)
break;
int x = rnd.Next(elits.Length - 1);
int y = rnd.Next(elits.Length - 1);
Tour parent1 = elits[x];
Tour parent2 = elits[y];
Tour child = CrossingOver(parent1, parent2);
int mut = rnd.Next(100);
if (mutPosibility >= mut)
{
child = Mutation(child);
}
population[currentPopSize] = child;
currentPopSize++;
}
progress = currentPopSize * 100 / population.Length;
this.Progress = progress;
GC.Collect();
}
if (GACompleted != null)
GACompleted(this, EventArgs.Empty);
});
}
In here "elits" are the chromosoms that have greater fit value than the average fit value of the population.
Scientific papers suggest smaller population. Maybe you should follow what is written by the other authors. Having big population does not give you any advantage.
TSP can be solved by GA, but maybe it is not the most efficient approach to attack this problem. Look at this visual representation of TSP-GA: http://www.obitko.com/tutorials/genetic-algorithms/tsp-example.php
Ok. I have just found a solution. Instead of using an array with size of maxPopulation, change new generations with the old and bad one who has bad fitness. Now, I am working with a less sized array, which has length of 10000. The length was 1,000.000 before and it was taking too much time. Now, in every iteration, select best 1000 chromosomes and create new chromosomes using these as parent and replace to old and bad ones. This works perfect.
Code sample:
public void StartAsync()
{
CreatePopulation(); //Creates chromosoms for starting
currentProducedPopSize = popNumber; //produced chromosom number, starts with the length of the starting population
while (currentProducedPopSize < maxPopNumber && !stopped)
{
Tour[] elits = ElitChromosoms();//Gets best 1000 chromosoms
Array.Reverse(population);//Orders by descending
this.Best = elits[0];
//Create new chromosom as many as the number of bad chromosoms
for (int i = 0; i < population.Length - elits.Length; i++)
{
if (currentProducedPopSize >= maxPopNumber || stopped)
break;
int x = rnd.Next(elits.Length - 1);
int y = rnd.Next(elits.Length - 1);
Tour parent1 = elits[x];
Tour parent2 = elits[y];
Tour child = CrossingOver(parent1, parent2);
int mut = rnd.Next(100);
if (mutPosibility <= mut)
{
child = Mutation(child);
}
population[i] = child;//Replace new chromosoms
currentProducedPopSize++;//Increase produced chromosom number
}
progress = currentProducedPopSize * 100 / maxPopNumber;
this.Progress = progress;
GC.Collect();
}
stopped = false;
this.Best = population[population.Length - 1];
if (GACompleted != null)
GACompleted(this, EventArgs.Empty);
}
Tour[] ElitChromosoms()
{
Array.Sort(population);
Tour[] elits = new Tour[popNumber / 10];
Array.Copy(population, elits, elits.Length);
return elits;
}
I was recently tripped up by the fact that the expected type of a setter that sets an Int is Int -> Int.
Why does a setter return a value? What significance does this value have?
Small addition to other answers over here, it allows you to do this:
x = y = z = 5;
The value that the setter returns is the value of the assignment expression.
For instance, if you were to do something like this:
public var x(setX, getX): Int
public function setX(val: Int): Int {
return 5;
}
static function main() {
neko.Lib.print(x = 2); // Prints 5
}
Haxe would print out 5. The setter returns the value of the set expression. Of course, it's a nonsensical value in this case.
In the real world, it permits a way of implementing copy by value on assignment, eg:
public var pos(set_pos, default):Point;
function set_pos(newPos:Point) {
pos.x = newPos.x
pos.y = newPos.y;
return pos;
}
And also of having a sensible return when implementing setters that can fail, eg:
public var positiveX(default, set_positiveX):Int;
function set_positiveX(newX:Int) {
if (newX >= 0) x = newX;
return x;
}
trace(x = 10); // 10
trace(x = -4); // 10
trace(x); // 10
Whereas you would otherwise get something like this:
trace(x = 10); // 10
trace(x = -4); // -4
trace(x); // 10
Which is what happens in AS3 even if the setter does not modify the value. If you could not do this, clearly the first, where x = -4 returns 10 is better :)