My object and it's clones(with a collider attached) are pooled and deactivated on swipe left or right. When they are activated, they immediateliy move along the direction of swipe. How can possibly set their respawn speed to zero?(horizontal movement)
I would make a script for the objects I wouldn't want to move and either attach it to each individual object or a manager based object which controls the spawned objects. You can simply after instantiating, set their speed variable to 0 and call a coroutine for x seconds and at the end of the coroutine it would change their speed variable back. Make sure each has its own variable for speed as to not affect the whole lot.
It would be something like this..
GameObject clone = (GameObject)Instantiate(prefab, new Vector3(0, 0, 0), Quaternion.identity);
// set speed to zero here.
StartCoroutine(WaitAndMove(2.0F));
And add this function
IEnumerator WaitAndMove(float waitTime) {
yield return new WaitForSeconds(waitTime);
// set speed back here
}
Related
When you select an object with FabricJS the depth is changed so that it appears on top of everything else. I'd like to stop this from happening.
The selection border and handles should be on top, but the object itself should be behind the other objects so that users can see how it will be positioned once they have finished moving it around.
Is there an easy way to do this?
I've now found out the answer. You have to pass preserveObjectStacking = true to the constructor.
eg
canvas = this.__canvas = new fabric.Canvas('YOUR_CANVAS_NAME', {preserveObjectStacking: true});
Pixijs (3.0.8) supports multi-touch as shown in their demos, and I've set up start, move and end listeners for touches on my mobile device.
The touches are registered on a square within the canvas which I'll call the interactiveArea, but the touchend events trigger when let go outside of the area as well. This is behavior that works fine with a single mouse cursor.
However, when using more fingers, having touches with the identifiers 0,1 and 2, only the first touchEnd is triggered outside of the area.
So I press and hold 3 fingers inside the interactiveArea and move them all outside of it. Then I let go of 1, and then the others. I won't be notified of touchEnds for event 0 and 2, and I'd have to re-register 3 touches and let go properly just to get a touchend for 2 triggered!
Any tips on how I can detect all touchends, rather than have it stop on the first touchend? I've tried working with a setTimeout hack as well, but that really doesn't suit my use case.
Edit I've made a basic codepen to demonstrate how touchendoutside is only triggered once. https://codepen.io/Thomaswithaar/pen/EygRjM Do visit the pen on mobile, as it is about touches rather than mouse interactivity.
Holding two fingers on the red square and then moving them out and letting go will only trigger one touchendoutside event.
Looking at the PIXI source code, there is indeed a bug in the Interaction Manager. Here is the method that processes touch end events:
InteractionManager.prototype.processTouchEnd = function ( displayObject, hit )
{
if(hit)
{
this.dispatchEvent( displayObject, 'touchend', this.eventData );
if( displayObject._touchDown )
{
displayObject._touchDown = false;
this.dispatchEvent( displayObject, 'tap', this.eventData );
}
}
else
{
if( displayObject._touchDown )
{
displayObject._touchDown = false;
this.dispatchEvent( displayObject, 'touchendoutside', this.eventData );
}
}
};
You can see in the else statement that a touchendoutside event gets dispatched when displayObject._touchDown is true. But after you release your first finger, it sets the flag to false. That is why you only receive that event once.
I've opened an issue here:
https://github.com/pixijs/pixi.js/issues/2662
And provided a fix here:
https://github.com/karmacon/pixi.js/blob/master/src/interaction/InteractionManager.js
This solution removes the flag and uses a counter instead. I haven't tested it yet, so please let me know if it works.
I'm trying to create a chart in winforms that databinds to a list in memory, and gets updated dynamically as the list changes. Here is my code:
open System
open System.Linq
open System.Collections
open System.Collections.Generic
open System.Drawing
open System.Windows.Forms
open System.Windows.Forms.DataVisualization
open System.Windows.Forms.DataVisualization.Charting
let link = new LinkedList<double>()
let rnd = new System.Random()
for i in 1 .. 10 do link.AddFirst(rnd.NextDouble()) |> ignore
let series = new Series()
let chart = new System.Windows.Forms.DataVisualization.Charting.Chart(Dock = DockStyle.Fill, Palette = ChartColorPalette.Pastel)
series.Points.DataBindY(link)
let form = new Form(Visible = true, Width = 700, Height = 500)
form.Controls.Add(chart)
let formloop = async {
while not chart.IsDisposed do
link.AddFirst((new System.Random()).NextDouble()) |> ignore
link.RemoveLast()
}
do
Async.StartImmediate(formloop)
Application.Run(form)
Console.WriteLine("Done")
Console.ReadLine() |> ignore
The async seems to work, but the chart never shows anything. It just shows a blank window. What am I doing wrong?
LinkedList<T> has no way to signal that it's been updated, so Chart has no way of knowing when to redraw itself.
In order for databinding to update the view, the source list must implement IBindingList and raise appropriate event when the contents change.
Separately, I must point out that it's dangerous to directly access UI properties/methods from non-UI threads (such as chart.IsDisposed in your code). In WinForms, this limitation is rarely actually enforced, so sometimes this might seem to work fine, only to crash later on a customer's machine with no way to attach a debugger.
You need to add the series to the SeriesCollection of the chart.
chart.Series.Add series
You need to construct a chart area and add it to the ChartAreaCollection of the chart.
let area = new ChartArea()
chart.ChartAreas.Add area
You need to make sure that the data binding method is called after the chart and form are set up.
...
form.Controls.Add chart
series.Points.DataBindY link
And now there's no way to communicate changes of your bound collection to the DataPointCollection of the series, as mentioned in Fyodor Soikin's answer. I'm not quite sure that IBindingList is an appropriate response;
while it's possible to hook into the ListChanged event, we could as well manipulate the series' DataPointCollection directly.
let formloop = async{
while not chart.IsDisposed do
series.Points.RemoveAt 0
series.Points.AddY(rnd.NextDouble()) |> ignore
do! Async.Sleep 100 }
Finally I'd like to point out this contribution by John Atwood which adresses both points raised by Fyodor; the data binding issue (by not using it) and the UI-thread safety issue.
I am using node.js and express, and I am calling server-side functions and syncing variables using nowjs. Suppose the user is drawn as a sprite on the canvas. His x,y coordinates are kept server-side in a "position" array.
Server-side:
position = { x : 0; y : 0 }
updatePosition = function (a,b)
{
playerPosition.x += a;
playerPosition.y += b;
}
Client-side:
if keypress('right'){ updatePosition(32,0); }
These are pseudocode. When the user presses the 'right' button, the server-side "updatePosition" function is called, which adds 32 (pixels) to the x-coordinate of the "position" array. This array is then shared with the client, and the new position is drawn on the canvas using client-side function.
Suppose I don't want to draw the sprite at the new position instantly. I want to play a walking animation that gradually moves the sprite 32 pixels to the right, and takes say 1 second to complete. I might implement it this way:
User presses the 'right' button.
The animation starts playing client-side.
updatePosition is called server-side as usual.
When animation on the client finishes, check if the final position client-side matches the coordinates stored server side.
When the user presses the 'right' button/key, he cannot repeat the keypress until 1 second later. The 1 second long "walking" animation has to complete and final position checked with the server-side coordinates before he can press 'right' again to move his sprite.
Question: How do I keep track of the 1 second server side? I can't do it client-side because the user will be able to hack his client to reduce the animation time.
Is the solution to "timestamp" the position array? E.g. position = { x : 0; y : 0, time: 0 }. If the user presses the 'right' button again, the server would check to see if the last position update was greater than 1 second ago. If less than 1 second, the server ignores it.
Why not simply storing a "lock" in the user session?
session.editLock = new Date().getTime();
When another edit is triggered by the client, just:
if(session.editLock && new Date().getTime() - session.editLock > 1000) {
// Return error
}
Modifying the position object doesn't feel right to me. A position object is meant to store position, not time.
MFC doc/view architecture, sdi (more precisely multiple top-level windows).
In my view class, I set my "playground" (i.e. logical space) with SetScrollSizes(); Then I want to limit maximum frame window size to that of view's maximum size.
Here is what I'm doing but I think there might be better solution, please advice:
I'm implementing OnGetMinMaxInfo() in my CMainFrame. There I try to get active view's scroll sizes, and set lpMMI->ptMaxTrackSize appropriately. Below is the code:
void CMainFrame::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
// Call base version:
CFrameWndEx::OnGetMinMaxInfo(lpMMI);
// Get active view:
CScrollView *pScrollView = (CScrollView *)GetActiveView();
if (pScrollView && pScrollView->IsKindOf(RUNTIME_CLASS(CMyFckinView)))
{
// Get total size of playground:
CSize sizePlayground = pScrollView->GetTotalSize();
// Test if the size is non-zero, i.e. there is at least one node displayed:
if (sizePlayground.cx && sizePlayground.cy/* && !IsPrintPreview()*/)
{
// Set maximum window size to match our playground size:
CRect rectClient, rectWindow;
pScrollView->GetClientRect(&rectClient);
this->GetWindowRect(&rectWindow);
if (rectWindow.top > -5000 && rectWindow.left > -5000) // Avoid when minimized...
{
lpMMI->ptMaxTrackSize.x = sizePlayground.cx + (rectWindow.Width() - rectClient.Width());
lpMMI->ptMaxTrackSize.y = sizePlayground.cy + (rectWindow.Height() - rectClient.Height());
return;
}
}
}
}
This works but has one problem: When print preview is displayed (standard MFC print preview), I obviously want to allow free window resizing, so I use runtime info GetActiveView()->IsKindOf(...) to determine that active view is really my view, and not print-preview's view (which is CPreviewViewEx). But when I close the print preview, OnGetMinMaxInfo is not called, so I'm unable to adjust frame size according to my view again. As soon as I move the window OnGetMinMaxInfo gets called again and correctly adjusts frame size, but without manually moving the window old size (to which the print preview was sized to) is retained and has ugly artifact.
What can I do? Basically if I could trap the moment when print preview is closed, I could use following trick:
// Trigger the WM_MINMAXINFO message:
CFrameWnd *pFrame = GetParentFrame();
RECT rectWindow;
pFrame->GetWindowRect(&rectWindow);
pFrame->MoveWindow(&rectWindow);
But I don't know how to trap print-preview closure.
What I'm trying to accomplish seems quite standard: who would want to have frame window resized bigger than view's logical size (set by SetScrollSizes())? So there should be some more natural solution maybe?
In your CMyFckinView, handle a message that is reliably sent when the print preview is closed and then post a user message to the mainframe which will trigger your "force minmax" code. Perhaps WM_FOCUS or WM_ACTIVATE?