Which of these 2 programming styles do you prefer? Why? Are there particular advantages to one over the other?
// Style 1
if (doBorder)
doTheBorder();
if (doFrame)
doTheFrame();
if (doDraw)
doTheDraw();
void doTheBorder()
{
// ...
}
void doTheFrame()
{
// ...
}
void doTheDraw()
{
// ...
}
// Style 2
doTheBorder();
doTheFrame();
doTheDraw();
void doTheBorder()
{
if (!doBorder)
return;
// ...
}
void doTheFrame()
{
if (!doFrame)
return;
// ...
}
void doTheDraw()
{
if (!doDraw)
return;
// ...
}
The first. The second seems to be... lacking in confidence. Why call doTheBorder() if you don't even know if you want the border to be done? IMO, you should assert that the border really needs doing, and then call doTheBorder() with confidence!
...Also, from a more technical point of view: if doTheBorder() is in a closed API, a developer in the distant future might call it and if the second style is employed, they may wonder why the border didn't get done, despite their call to doTheBorder(). Of course, sometimes certain circumstances or restrictions or limitations may dictate that the second style be used, but I'd avoid it when possible.
Related
I am creating a custom renderer, that needs to display whatever I have rendered in my Vulkan engine. For this I have a VulkanSurfaceView, which inherits from MetalKit.MTKView on iOS, and from Android.Views.SurfaceView and ISurfaceHolderCallback on Android.
For iOS I can simply do this, which will draw a new frame continually, as long as the view is in focus:
public class VulkanSurfaceView : MTKView, IVulkanAppHost
{
...
public override void Draw()
{
Renderer.Tick();
base.Draw();
}
}
However, on Android I have to do this, where I call Invalidate() from within the OnDraw method, else it is only called once. I think this code smells a bit, and I am not sure, if this is the "good" way of doing it. Is my solution okay? If not, does anyone have a better idea?
public class VulkanSurfaceView : SurfaceView, ISurfaceHolderCallback, IVulkanAppHost
{
...
protected override void OnDraw(Canvas? canvas)
{
Renderer.Tick();
base.OnDraw(canvas);
Invalidate();
}
}
Did you try calling setWillNotDraw(false) in your surfaceCreated method ?
Refer the link
Thank you to #ToolmakerSteve.
I created a Timer where I call Invalidate() if a new frame has been requested (by me via a simple bool). For anyone interested I do it like so:
protected override void OnDraw(Canvas? canvas) // Just to show the updated OnDraw-method
{
Renderer.Tick();
base.OnDraw(canvas);
}
public void SurfaceCreated(ISurfaceHolder holder)
{
TickTimer = new System.Threading.Timer(state =>
{
AndroidApplication.SynchronizationContext.Send(_ => { if (NewFrameRequested) Invalidate(); }, state);
try { TickTimer.Change(0, Timeout.Infinite); } catch (ObjectDisposedException) { }
}, null, 0, Timeout.Infinite);
}
For now it is very simple, but it works and will probably grow. The reason for my initial bad framerate with this method was a misunderstanding of the "dueTime" of the Timer (see Timer Class), which I though was the framerate sought. This is actually the time between frames, which seems obvious now.
As #Bhargavi also kindly mentioned you need to set "setWillNotDraw(false)" if OnDraw is not being called when invalidating the view.
i have an example : player object, obstacle_1 object and obstacle_2 object. How do I check which one player collides with? I mean I want to do script_1 for colliding player with obstacle_1 and do script_2 when player collides with obstacle_2. Example:
private void OnTriggerEnter2D(Collider2D collision)
{
//script 1 when this object(player) collides with obstacle_1;
//script 2 when this object(player) collides with obstacle_2;
}
It seems like you're asking how to differentiate between objects. There are many ways of doing so, and it's hard to say which will work best for you since you didn't give a lot of context. Here are some ideas:
One of the simplest ways would be comparing the object's names:
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.name == "Obstacle_1"){
//React to obstacle 1
}
else if (collision.gameObject.name == "Obstacle_2"){
//React to obstacle 2
}
}
I really wouldn't encourage this though, since the name of the objects can be changed quite easily.
You could add Tags to obstacle_1 and obstacle_2, and compare tags, like:
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.CompareTag("Obstacle 1")){
//React to obstacle 1
}
else if (collision.gameObject.CompareTag("Obstacle 2")){
//React to obstacle 2
}
}
This is a bit better, since changing tags is not as easy as changing names, but there's still room for spelling errors. Comparing strings is not very efficient either, especially if done frequently.
You could create different components for obstacle_1 (BouncyObstacle) and obstacle_2 (SpikeObstacle), and then have your player try to get these components, like:
private void OnTriggerEnter2D(Collider2D collision) {
if(collision.gameObject.TryGetComponent(out BouncyObstacle bouncyObs){
// React to bouncy obstacle
}
else if(collision.gameObject.TryGetComponent(out SpikeObstacle spikeObs)
{
//React to spike obstacle
}
}
This is a little bit better, but every time you want to add a new obstacle, you need to add an if to your player code.
Again, it's hard to say which solution would be best. From your snippet, it seems like the player class is responsible for reacting to the obstacles, and this means that every time you want to add a new obstacle, you need to open the player class and change the OnTriggerEnter method. Perhaps it would be better to move this responsibility to separate components. That way you'll be able to add as many obstacles you want without changing any of the previous classes you made. Something like:
public class BouncyObstacle : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
if(other.TryGetComponent(out Player player))
{
player.Bounce();
}
}
}
public class SpikeObstacle : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
if(other.TryGetComponent(out Player player))
{
player.Kill();
}
}
}
// etc..
I am trying to develop an app using Xamarin.Forms. At a certain point I am trying to have multiple switches that are grouped. This is to say that when one switch is toggled, every other switch needs to be untoggled and, at the same time, there needs to be at least one switch always toggled. This is to say that tapping on a switch that is already toggled should not change anything.T
Now my problem is that Xamarin.forms Toggled event for switches can be fired from the UI, but is also fired programmatically. I thought I had found a way around this problem, but still by doing:
-If the switch was turned on, turn off all others and do application stuff.
-else if a switch was turned off, check if there are any others that are on. If not, turn the switch back on. If yes, do nothing.
A sample code for two switches could be:
private void OnFirstToggled(object sender, EventArgs args)
{
if(FirstSwitch.isToggled)
{
//Application stuff.
SecondSwitch.isToggled = false;
}
else if (!SecondSwitch.isToggled)
{
FirstSwitch.isToggled = true;
}
}
private void OnSecondToggled(object sender, EventArgs args)
{
if(SecondSwitch.isToggled)
{
//Application stuff.
FirstSwitch.isToggled = false;
}
else if (!FirstSwitch.isToggled)
{
SecondSwitch.isToggled = true;
}
}
This solution results in an infinite loop when an already toggled switch is tapped. In fact, the isToggled property of the switch alternates between true and false infinitely. However when debugging the other event never seems to be fired (or at least my debugger does not see it). This is why I don't understand where the isToggled property is changed after that first tap.
I know this is probably a very simple issue, but I cannot seem to find the solution somewhere online. Can anyone see the problem or recommend a better, common way to implement this?
I write a simple solution to you to always keep one Switch open from a Switch group.
Let's first add three switch for test, make sure these Switch will fire the same event of Toggled:
<StackLayout>
<!-- Place new controls here -->
<Switch Toggled="Switch_Toggled" x:Name="FirstSwitch"/>
<Switch Toggled="Switch_Toggled" x:Name="SecondSwitch"/>
<Switch Toggled="Switch_Toggled" x:Name="ThirdSwitch"/>
</StackLayout>
In the code behind, I add those Switches into a list, and loop them in Switch_Toggled event to open/close the Switches:
public partial class MainPage : ContentPage
{
List<Switch> switchList;// To store all your Switches
bool isLooping; //To make sure the Switch_Toggled metod not fired a second time during one toogle event
public MainPage()
{
InitializeComponent();
switchList = new List<Switch>();
switchList.Add(FirstSwitch);
switchList.Add(SecondSwitch);
switchList.Add(ThirdSwitch);
isLooping = false;
}
private void Switch_Toggled(object sender, ToggledEventArgs e)
{
//To make sure the Switch_Toggled metod not fired a second time during one toogle event
if (isLooping == true)
{
return;
}
isLooping = true;
Switch clickSwitch = sender as Switch;
clickSwitch.IsToggled = true;
foreach (var tempSwitch in switchList)
{
if (tempSwitch != clickSwitch)
{
if (tempSwitch.IsToggled == true)
{
tempSwitch.IsToggled = false;
}
}
}
isLooping = false;
}
}
You can try this solution and feel free to ask me any question if you don't understand.
Your problem are the two else blocks. Take in account that you're toggling it on anyway.
I am trying to achieve smooth animation using Xamarin SkiaSharp. The core issue is the the time between calling canvasView.InvalidateSurface(); and hitting the mathod OnCanvasViewPaintSurface to do the redraw can vary from 3 to 30 ms which gives a somewhat jerky appearance when you are moving an object across the screen. I have tried to mitigate this by adding a dead loop in the draw code, which helps some but is not a great solution. I do not understand why the time varies so much, and I do not see any way around this. You cannot put a sleep in the draw code. How do games achieve smooth animation? My code follows
async Task DoAnimationLoop()
{
while (DoAnimation)
{
AccumulatedTime = StopWatch1.ElapsedMilliseconds;
await Task.Delay(TimeSpan.FromMilliseconds(5));
if (AccumulatedTime > 50)
{
StopWatch1.Restart();
MoveItems();
SKCanvasView canvasView = Content as SKCanvasView;
TotalBounds = new Size(canvasView.Width,
canvasView.Height);
canvasView.InvalidateSurface();
}
}
}
private void OnCanvasViewPaintSurface(object sender,
SKPaintSurfaceEventArgs e)
{
AccumulatedTime = StopWatch1.ElapsedMilliseconds;
while (AccumulatedTime < 30)
{
AccumulatedTime = StopWatch1.ElapsedMilliseconds;
}
e.Surface.Canvas.Clear();
e.Surface.Canvas.DrawBitmap(Background, 0, 0);
foreach(Item item in AllItems)
{
e.Surface.Canvas.DrawBitmap(item.CurrentBitmap,
item.CurrentPositionX, item.CurrentPositionY);
}
}
For future readers:
From experience, I get the smoothest animations with SkiaSharp by creating SkiaSharp SKCanvasViews that have Bindable properties that can be incremented with Xamarin.Forms.Animate. Animate handles all the timing and sleeping code based on variables you configure it with. As you want a loop, you can set the repeat delegate to return true when calling Animate.Commit( ... repeat: () => true ...)
Here is a method example that animates a progress bar "filling" to 100 percent (without looping), by incrementing the ProgressBar's PercentageFilled Property. Note the timing settings you can configure: Refresh rate = 11ms (equates to "90 fps": 1000ms/90 = 11.11), timeToAnimate is the length of time the animation should take to complete in ms, and you can choose from several easing functions.
private void AnimateProgressBar()
{
double startPercentage = 0; //start at 0 percent
double endPercentage = 1; //fill to 100 percent (Forms.Animate will evenly increment
//between 0 and 1 , and in this case the ProgressBar's OnPaintSurface method knows how to draw based
//on the given decimal i.e. if PercentageFilled is .5 it will draw the bar to
//50 percent of its possible max length)
uint timeToAnimate = 1000;
Xamarin.Forms.Animation animation = new Animation(v => _ProgressBar.PercentageFilled = (float)v, startPercentage, endPercentage, easing: Easing.CubicOut);
animation.Commit(_ProgressBar, "FillPercentage", length: timeToAnimate, finished: (l, c) => animation = null, rate: 11);
}
When the PercentageFilled Property is changed it triggers InvalidateSurface by placing a call to InvalidateSurface() within the OnPropertyChanged method. To do this override OnPropertyChanged like so in your SKCanvasView derived class:
class ProgressBar: SKCanvasView
{
//...
public BindableProperty PercentageFilledProperty =
BindableProperty.Create(nameof(PercentageFilled), typeof(float), typeof(ProgressBar), 0f);
public float PercentageFilled
{
get { return (float)GetValue(PercentageFilledProperty ); }
set { SetValue(PercentageFilledProperty , value); }
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
InvalidateSurface();
}
protected override void OnPaintSurface(SKPaintSurfaceEventArgs args)
{
//Draws progress bar based on the PercentageFilled filled property
}
//....
}
In the question's code it appears that a lot of items are being moved (MoveItems();) in sequence and this technique of drawing items one by one moving might be the cause of jitter? But MoveItems appears to be the place where you might want to use Forms.Animate that is you could Create a Forms.Animation with MoveItems() as the Callback. Look into the microsoft documentation for "Custom Animations in Xamarin.Forms" for more info on how to animate with callbacks.
Also check out "The basics to create custom Xamarin.Forms controls using SkiaSharp" by Konrad Müller on Medium which contains this helpful paragraph which might be useful to consider if you are making a game:
The basic SkiaSharp.Views.Forms provides two views you can use as a
base for your controls: SKCanvasView and SKGLView. The CanvasView uses
the CPU accelerated backend while the GLView uses OpenGL and therefore
the GPU. You might intuitively think that using the GPU for graphics
operations is always the better choice but in fact, OpenGL has a high
overhead when creating the GL context. The CanvasView simply allocates
the memory it needs and as long as enough CPU power is available, it
can render without problems. In theory, the CanvasView should be
better suited for less demanding renderings and GlView better for
complex renderings but the power of modern smartphones makes these
differences mostly unnoticable. I would recommend to simply stick to
the CanvasView and switch to the GlView if the rendering gets to
complex and you notice performance problems.
I've been developing with QT for around a week now and am pleased to say that I'm picking it up really fast. I'm an intermediate C++ programmer but picking up some parts of QT is proving to be challenging. I need to process key press events from the QPlainTextEdit when the user presses enter and I presume that the solution will involve sub classing the widget. Can any of you smart guys give me a potential implementable solution?
To really understand Qt and event handling there are two key areas of the documentation you should read. The first is the overview on The Event System and the second is a very important bit which is a cleverly hidden link on that page for QCoreApplication::notify. They should really move that to the main page of the Event System documentation as it really makes things quite clear (to me at least).
If you only need to handle some messages sent to the control - like the key-presses - there is no need to subclass it. You can alternatively use the event filtering mechanism. Here is a simple example:
Provide virtual eventFilter method in one of your QObject-based classes (e.g. the window form class).
bool MyWindow::eventFilter(QObject *watched, QEvent *event)
{
if(watched == ui->myTargetControl)
{
if(event->type() == QKeyEvent::KeyPress)
{
QKeyEvent * ke = static_cast<QKeyEvent*>(event);
if(ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter)
{
// [...]
return true; // do not process this event further
}
}
return false; // process this event further
}
else
{
// pass the event on to the parent class
return QMainWindow::eventFilter(watched, event);
}
}
Install your class as the event filter for the target control. Form constructor is usually a good place for this code. In the following snippet this refers to the instance of class in which you implemented the eventFilter method.
ui->myTargetControl->installEventFilter(this);
i would try subclassing QPlainTextEdit and reimplementing QWidget::keyPressEvent:
void YourTextEdit::keyPressEvent ( QKeyEvent * event )
{
if( event->key() == Qt::Key_Return )
{
// optional: if the QPlainTextEdit should do its normal action
// even when the return button is pressed, uncomment the following line
// QPlainTextEdit::keyPressEvent( event )
/* do your stuff here */
event->accept();
}
else
QPlainTextEdit::keyPressEvent( event )
}
please try :
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter){
//do something
}
in your keyPressEvent() function.