Processing(Java)中基于鼠标坐标绘制箭头:多次绘制位置异常问题排查
问题分析与解决方案
你的箭头绘制程序出现后续箭头位置错误的问题,主要出在三个核心细节上:PVector的原地修改特性、坐标变换未做隔离,以及鼠标起点的获取逻辑。让我一步步拆解并修复:
1. PVector的sub()方法会原地修改原对象
PVector的sub()、add()这类实例方法默认会直接修改调用它的PVector本身,而不是返回一个全新的向量。比如你在draw()里写的:
drawArrow(lineBase, arrowTip.sub(lineBase));
这行代码执行后,arrowTip已经被改成了相对lineBase的偏移量,而非原来的绝对坐标。后续保存vec[i].x=arrowTip.x时,存的已经是错误的相对坐标,直接导致重绘时位置混乱。
同样,drawSavedArrows()里的vector.sub(base[i])会修改全局的vector对象,让所有后续箭头复用被篡改过的向量。
修复方案:使用PVector.sub(a, b)静态方法,它会返回一个新的PVector,完全不影响原数据:
// 替换draw()中的调用 drawArrow(lineBase, PVector.sub(arrowTip, lineBase)); // 替换drawSavedArrows()中的调用 drawArrow(base[i], PVector.sub(vec[i], base[i]));
2. 坐标变换未用pushMatrix()/popMatrix()隔离
你的drawArrow()方法使用了translate()和rotate(),但没有在开头保存当前坐标状态,结尾恢复状态。这会导致后续所有绘制元素(包括其他箭头)都继承这个变换后的坐标系统,位置彻底错乱。
修复方案:用pushMatrix()和popMatrix()包裹坐标变换逻辑:
void drawArrow(PVector base, PVector vector) { strokeWeight(height / 50); fill(20, 85, 30, 180); stroke(20, 85, 30, 180); pushMatrix(); // 保存当前坐标系统状态 translate(base.x, base.y); line(0, 0, vector.x, vector.y); rotate(vector.heading()); int arrowSize = height / 20; translate(vector.mag() - arrowSize, 0); triangle(0, arrowSize / 1.5, 0, -arrowSize / 1.5, arrowSize, 0); popMatrix(); // 恢复原始坐标系统,不影响后续绘制 }
3. 鼠标按下时的起点获取错误
你在mousePressed()里用了pmouseX/pmouseY,但右键按下时,pmouseX是按下前的鼠标位置,应该直接用mouseX/mouseY作为箭头起点:
// 替换mousePressed()中的起点赋值 lineBase.x = mouseX; lineBase.y = mouseY; base[i].x = mouseX; base[i].y = mouseY;
修改后的完整代码
PVector arrowTip = new PVector(); PVector lineBase = new PVector(); PVector [] base = new PVector[100]; PVector [] vec = new PVector[100]; boolean drawing; int flag=0; void settings() { float hg=displayHeight/1.1; int wd=(int)hg*10/8; size(wd, (int)hg); drawing=false; } void draw() { background(255); // 绘制正在拖拽的箭头 if (flag == 1) { arrowTip.x = mouseX; arrowTip.y = mouseY; drawArrow(lineBase, PVector.sub(arrowTip, lineBase)); } // 重绘已保存的箭头 drawSavedArrows(); } void drawSavedArrows() { for (int i =0; i<base.length; i++) { if (vec[i]!=null && base[i]!=null) { drawArrow(base[i], PVector.sub(vec[i], base[i])); } } } void drawArrow(PVector base, PVector vector) { strokeWeight(height / 50); fill(20, 85, 30, 180); stroke(20, 85, 30, 180); pushMatrix(); translate(base.x, base.y); line(0, 0, vector.x, vector.y); rotate(vector.heading()); int arrowSize = height / 20; translate(vector.mag() - arrowSize, 0); triangle(0, arrowSize / 1.5, 0, -arrowSize / 1.5, arrowSize, 0); popMatrix(); } void mousePressed() { if (mouseButton == RIGHT) { lineBase.x = mouseX; lineBase.y = mouseY; for (int i =0; i<base.length; i++) { if (base[i]==null) { base[i] = new PVector(mouseX, mouseY); break; } } drawing=true; } else if(mouseButton == LEFT){ for (int i=0; i<base.length; i++) { if (base[i]==null) { break; } base[i]=null; vec[i]=null; } } } void mouseDragged() { if (mouseButton == RIGHT) { flag = 1; } } void mouseReleased() { flag = 0; if (drawing) { for (int i =0; i<vec.length; i++) { if (vec[i]==null) { vec[i] = new PVector(mouseX, mouseY); break; } } } drawing=false; }
额外优化说明
- 移除了多余的全局变量
vector、xx、yy,直接用PVector静态方法处理,减少出错点 - 保存箭头尖端时直接使用
mouseX/mouseY,不再依赖arrowTip,逻辑更简洁
修改后你就能正常绘制多个箭头,每个箭头的位置和方向都会正确显示了。
内容的提问来源于stack exchange,提问作者yoyo
相关产品推荐
相关产品推荐

