c# - 在 Xamarin 中使用 CocoSharp 绘制移动图表会导致帧速率变慢
问题描述
我正在制作一个显示加速度计折线图的应用程序。图表必须横向移动以显示新结果。绘制我使用 CocoSharp 图形库。
第一次尝试是每次更新都重新绘制完整的图表,但这不够快,而且你不能以某种方式绘制透明,这不会擦除以前绘制的像素,所以我的图表刚刚填满。
第二次尝试是让图表比屏幕宽 4 倍,并且只在 2 个位置绘制最后一次更新:在我们正在绘制的位置和 2 个屏幕宽度后面(屏幕外)。在画线之前,我画了一条黑线而不是透明线来擦除以前的结果。
然后我将整个图层向左移动,给出一个漂亮的滚动图表。然后当位置超过 2 个屏幕宽度时,我将位置重置回 0,但是因为我们在 2 个位置绘制图形已经绘制与我们离开的位置相同,使其永远无缝滚动。
这效果很好,但在绘制几分钟后,您会注意到屏幕开始出现帧率滞后。我调查了一切,但我的绘图线程工作得很好,每 16 毫秒抽出一次完整的更新,所以我认为它是 CocoSharp 库。
正如我之前所说,当您绘制透明时,像素不会被擦除,这让我认为每次绘制更新都会以某种方式保存在内存中,一段时间后会减慢 gpu 的速度。这可能是正确的吗?如果是这样,我该如何解决?
using CocosSharp;
using JumpMeter.Shared;
using JumpMeter.Shared.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace JumpMeter
{
public class ChartLayer
{
public ChartLayer(CCScene scene, float x, float y, float width, float height)
{
List = new ConcurrentQueue<CalculationLog>();
RasterLayer = new CCLayer();
RasterNode = new CCDrawNode();
GraphLayer = new CCLayer();
GraphNode = new CCDrawNode();
// Add the background layer
RasterLayer.AddChild(RasterNode);
// Draw the "zero lines"
RasterNode.DrawLine(new CCPoint(0, height / 2), new CCPoint(width, height / 2), 0.1f, CCColor4B.White);
RasterNode.DrawLine(new CCPoint(0, 2), new CCPoint(width, 2), 0.1f, CCColor4B.White);
scene.AddLayer(RasterLayer);
// Add the graphics layer
GraphLayer.AddChild(GraphNode);
scene.AddLayer(GraphLayer);
Width = width;
Height = height;
RasterLayer.PositionX = x;
RasterLayer.PositionY = y;
GraphLayer.PositionY = y;
}
public CCLayer RasterLayer { get; }
public CCDrawNode RasterNode { get; }
public CCLayer GraphLayer { get; }
public CCDrawNode GraphNode { get; }
float Width { get; }
float Height { get; }
// Buffer for the drawn items
ConcurrentQueue<CalculationLog> List { get; }
// Current position of the graph
float Position { get; set; }
// Here we get the new values for the graph
public void AddValue(CalculationLog value)
{
List.Enqueue(value);
}
// This function will be called every 16ms
public bool Draw()
{
while (List.TryDequeue(out CalculationLog value))
{
Position += Constants.GraphSpeed; // = 0.1f
// If the position is bigger than 2 screen widths (* 1000 for ultra slow speeds)
if (Convert.ToInt32(Position * 1000) >= Convert.ToInt32(Width * 2 * 1000))
Position = 0;
// Calculate real positions
var x = Position + RasterLayer.PositionX;
var y = Convert.ToSingle(value.AccelerationUp / Constants.Scale) * (Height / 2) + Height / 2;
if (y > Height) y = Height;
if (y < 0) y = 0;
var y2 = Convert.ToSingle(value.Height / Constants.Scale * 2) * (Height / 2) + 1;
if (y2 > Height) y2 = Height;
if (y2 < 0) y2 = 0;
// Then draw them
GraphNode.DrawLine(new CCPoint(x, 0), new CCPoint(x, Height), Constants.GraphSpeed, CCColor4B.Black);
GraphNode.DrawLine(new CCPoint(x, Height / 2), new CCPoint(x, y), Constants.GraphSpeed, CCColor4B.White);
GraphNode.DrawLine(new CCPoint(x, y2), new CCPoint(x, y2 + 1), Constants.GraphSpeed, CCColor4B.White);
GraphNode.DrawLine(new CCPoint(x - Width * 2, 0), new CCPoint(x - Width * 2, Height), Constants.GraphSpeed, CCColor4B.Black);
GraphNode.DrawLine(new CCPoint(x - Width * 2, Height / 2), new CCPoint(x - Width * 2, y), Constants.GraphSpeed, CCColor4B.White);
GraphNode.DrawLine(new CCPoint(x - Width * 2, y2), new CCPoint(x - Width * 2, y2 + 1), Constants.GraphSpeed, CCColor4B.White);
}
// Move the position of the graph layer
GraphLayer.PositionX = Convert.ToInt32(Width - Position);
return true;
}
}
}
(我实际上是在 1 个图中绘制 2 个图,我在一般描述中忘记了这一点)
解决方案
好吧,看来我是对的。在没有绘制图表的情况下对其进行测试后,应用程序并没有开始口吃。我现在将图表更改为使用 2 层,方式与我过去所做的几乎相同,只是当我重置滚动时,我还重置了之前的 CCDrawNode :
GraphNode.Clear();
完整代码:
public class ChartLayer
{
public ChartLayer(CCScene scene, float x, float y, float width, float height)
{
List = new ConcurrentQueue<ICalculationLog>();
RasterLayer = new CCLayer();
RasterNode = new CCDrawNode();
GraphLayer1 = new CCLayer();
GraphNode1 = new CCDrawNode();
GraphLayer2 = new CCLayer();
GraphNode2 = new CCDrawNode();
// Add the background layer
RasterLayer.AddChild(RasterNode);
// Draw the "zero lines"
RasterNode.DrawLine(new CCPoint(0, height / 2), new CCPoint(width, height / 2), 0.1f, CCColor4B.White);
RasterNode.DrawLine(new CCPoint(0, 2), new CCPoint(width, 2), 0.1f, CCColor4B.White);
scene.AddLayer(RasterLayer);
// Add the graphics layer
GraphLayer1.AddChild(GraphNode1);
scene.AddLayer(GraphLayer1);
GraphLayer2.AddChild(GraphNode2);
scene.AddLayer(GraphLayer2);
Width = width;
Height = height;
RasterLayer.PositionX = x;
RasterLayer.PositionY = y;
GraphLayer1.PositionY = y;
GraphLayer2.PositionY = y;
}
public CCLayer RasterLayer { get; }
public CCDrawNode RasterNode { get; }
bool Node1Selected = false;
public CCLayer GraphLayerForeground => Node1Selected ? GraphLayer1 : GraphLayer2;
public CCDrawNode GraphNodeForeground => Node1Selected ? GraphNode1 : GraphNode2;
public CCLayer GraphLayerBackground => Node1Selected ? GraphLayer2 : GraphLayer1;
public CCDrawNode GraphNodeBackground => Node1Selected ? GraphNode2 : GraphNode1;
public CCLayer GraphLayer1 { get; }
public CCDrawNode GraphNode1 { get; }
public CCLayer GraphLayer2 { get; }
public CCDrawNode GraphNode2 { get; }
float Width { get; }
float Height { get; }
// Buffer for the drawn items
ConcurrentQueue<ICalculationLog> List { get; }
// Current position of the graph
float Position { get; set; }
// Here we get the new values for the graph
public void AddValue(ICalculationLog value)
{
List.Enqueue(value);
}
// This function will be called every 16ms
public void Draw()
{
while (List.TryDequeue(out ICalculationLog value))
{
Position += Constants.GraphSpeed; // = 0.1f
// If the position is bigger than 2 screen widths (* 1000 for ultra slow speeds)
if (Convert.ToInt32(Position * 1000) >= Convert.ToInt32(Width * 2 * 1000))
{
Position = 0;
Node1Selected = !Node1Selected;
GraphNodeBackground.Clear();
}
// Calculate real positions
var x = Position + RasterLayer.PositionX;
var y = Convert.ToSingle((value.Acceleration.Z - 1) / Constants.Scale) * (Height / 2) + Height / 2;
if (y > Height) y = Height;
if (y < 0) y = 0;
var y2 = Convert.ToSingle(value.Height / Constants.Scale * 2) * (Height / 2) + 1;
if (y2 > Height) y2 = Height;
if (y2 < 0) y2 = 0;
// Then draw them
//GraphNode1.DrawLine(new CCPoint(x, 0), new CCPoint(x, Height), Constants.GraphSpeed, CCColor4B.Black);
GraphNodeForeground.DrawLine(new CCPoint(x, Height / 2), new CCPoint(x, y), Constants.GraphSpeed, CCColor4B.White);
GraphNodeForeground.DrawLine(new CCPoint(x, y2), new CCPoint(x, y2 + 1), Constants.GraphSpeed, CCColor4B.White);
//GraphNode1.DrawLine(new CCPoint(x - Width * 2, 0), new CCPoint(x - Width * 2, Height), Constants.GraphSpeed, CCColor4B.Black);
GraphNodeBackground.DrawLine(new CCPoint(x - Width * 2, Height / 2), new CCPoint(x - Width * 2, y), Constants.GraphSpeed, CCColor4B.White);
GraphNodeBackground.DrawLine(new CCPoint(x - Width * 2, y2), new CCPoint(x - Width * 2, y2 + 1), Constants.GraphSpeed, CCColor4B.White);
}
// Move the position of the graph layer
GraphNodeForeground.PositionX = Convert.ToInt32(Width - Position);
}
public void Clear()
{
GraphNode1.Clear();
}
}
推荐阅读
- javascript - 如何在反应js中通过悬停切换多个下拉列表
- tensorflow - Tensorflow:如何找出 BIG 张量?
- javascript - componentDidMount 不渲染
- spring - Gradle Multi Module Project:将模块依赖应用于除自身之外的所有子项目
- android - 使用我的 android 应用程序打开特定文件
- c# - 有没有办法在 c# 中为 Oledb 找到异常详细信息?
- ruby-on-rails - Redis 如何管理未使用的缓存键?
- python - 我试图安装 Tkinter
- python-3.x - 本地目录阴影 3rd 方包
- php - 网站背景的全屏视频需要很长时间才能加载到网站