【问题标题】:Is there a way to make a circle cover up another circle inside when I shrink the outer circle当我缩小外圈时,有没有办法让一个圆圈覆盖里面的另一个圆圈
【发布时间】:2021-11-04 06:36:11
【问题描述】:

我正在尝试制作眼睛,因为为什么不这样做,所以我正在尝试制作闪烁的动画。

我没有选择闭合“眼睑”圆圈,而是选择沿 y 轴收缩巩膜(白色位),这样看起来眼睛正在闭合。

现在我在中心添加彩色角膜,但是当我尝试在巩膜和角膜的 y 值相遇时缩小角膜时,角膜看起来很奇怪,就像被压扁了一样。

有什么方法可以让我缩小巩膜圈时,当外圈的边界小于内圈时,角膜圈会消失?

基本上就像您将 JPanel 调整为小于组件时发生的情况一样。它们只是消失在框架的边框下而不是出现在边框之外。

代码: 面板类:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class EyePanel extends JPanel implements ActionListener{

    private int width;
    private int height;

    private int timeStep = 10;
    
    private Timer timer;
    private Random random;
    
    Eye eye;
    
    EyePanel(int width, int height){
        this.width = width;
        this.height = height;
        
        eye = new Eye(width, height, timeStep);
        
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        this.setPreferredSize(new Dimension(width, height));
        
        
        frame.add(this);
        frame.pack();
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        
        
        timer = new Timer(timeStep, this);
        random = new Random();
        
        timer.start();
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        
        this.setBackground(new Color(255,255,255));
        
        draw(g);
    }
    
    public void draw(Graphics g) {
        eye.draw(g);
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        repaint();
    }
}

眼睛类:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.*;
import javax.swing.*;

public class Eye {

    private int width;
    private int height;
    private int timeStep;
    private int lidDiameter;
    private int sclDiameter;
    private int corDiameter;

    //lid coordinates
    private int lidX;
    private int lidY;

    //sclera coordinates
    private int sclX;
    private int sclY;
    private int sclU;           //upper level
    private int sclB;           //bottom level
    private int sclC;           //y-level at which eyes are closed

    //cornea coordinates
    private int corX;
    private int corY;
    private int corU;           //upper level
    private int corB;           //bottom level
    private int corC;           //y-level at which eyes are closed

    private int blinkDelay = 3; //delay in seconds preset
    private int blinkTime;      //time till next blink
    private int rate = 20;          //rate of eye close&open

    private boolean closed = false;

    Eye(int width, int height, int timeStep){
        this.width = width;
        this.height = height;
        this.timeStep = timeStep;

        blinkTime = blinkDelay*(1000/timeStep);

        //setup eye variables
        if(width>height)        lidDiameter = height - (height/10);
        else if(height>width)   lidDiameter = width - (width/10);
        else                    lidDiameter = width - (height/10);
        
        sclDiameter = lidDiameter-(lidDiameter/10);
        corDiameter = sclDiameter/3;

        //lid location
        lidX = (int)((width-lidDiameter)/2);
        lidY = (int)((height-lidDiameter)/2);
        //lid location
        
        //sclera location
        sclX = (int)(lidX + (lidDiameter-sclDiameter)/2);
        sclY = (int)(lidY + (lidDiameter-sclDiameter)/2);
        sclU = sclY;
        sclB = sclDiameter;
        sclC = (int)(sclY+sclDiameter/2);
        //sclera location
        
        //cornea location
        corX = (int)(sclX + (sclDiameter-corDiameter)/10);
        corY = (int)(sclY + (sclDiameter-corDiameter)/10);
        corU = corY;
        corB = corDiameter;
        corC = (int)(corY+corDiameter/2);
        //cornea location
        
        //setup eye variables
    }

    public void close() {
        if(sclU != sclC)
            sclU+= rate;

        if(sclB != sclC)
            sclB-= rate*2;          //bottom limit must rise by (required amt + rate of upper limit fall)

        if(sclU >= sclC && sclB <= sclC)
            closed = true;
    }

    public void open() {
        if(sclU != sclY)
            sclU+= -rate;

        if(sclB != sclDiameter)
            sclB-= -rate*2;         //bottom limit must rise by (required amt + rate of upper limit fall)

        if(sclU == sclY && sclB == sclDiameter) {
            closed = false;
            blinkTime = blinkDelay*(1000/timeStep);
        }
    }

    public void blink() {
        if(blinkTime == 0) {
            if(!closed)
                close();
            if(closed)
                open();
        }
        else
            blinkTime--;
    }

    public void draw (Graphics g) {
        Graphics2D g2d = (Graphics2D) g;

        //eyelid
        g2d.setColor(Color.pink);
        g2d.fillOval(lidX, lidY, lidDiameter, lidDiameter);

        //sclera
        g2d.setColor(Color.white);
        g2d.fillOval(sclX, sclU, sclDiameter, sclB);

        g2d.setColor(Color.black);
        g2d.drawLine(sclX, sclC, sclX + sclDiameter, sclC);

        //cornea
        g2d.setColor(Color.cyan);
        g2d.fillOval(corX, corU, corDiameter, corB);

        g2d.setColor(Color.red);
        g2d.drawLine(corX, corC, corX + corDiameter, corC);

        //trigger blink
        blink();
    }
}

启动一切的主类:

public class Main {

    public static void main(String[] args) {
        new EyePanel(600, 600);
    }
}

【问题讨论】:

  • 你的代码在哪里?
  • 好吧,这不是一个真正的代码错误,但我会在一秒钟内添加它
  • 但是当我尝试在巩膜和角膜的 y 值相遇时缩小角膜时, - 1) 角膜没有在眼睛的中心涂抹 2)角膜不收缩。所以我看不到你描述的行为。 minimal reproducible example 的目的是演示问题,以便我们可以准确地看到正在发生的事情。
  • 请修剪您的代码,以便更容易找到您的问题。请按照以下指南创建minimal reproducible example

标签: java swing graphics2d


【解决方案1】:

在任何情况下,绘画方法都不应调用任何形式的改变对象状态的逻辑。绘画是由系统事件触发的,你几乎无法控制它的时间。 (此类事件的示例包括用户移动窗口、降低或升高窗口、取消图标化窗口、解锁屏幕,甚至将鼠标移到窗口上。)

所以,你要做的第一件事就是从 Eye 类中删除它:

//trigger blink
blink();

...并将其添加到您的 actionPerformed 方法中:

@Override
public void actionPerformed(ActionEvent e) {
    eye.blink();
    repaint();
}

几乎所有 Swing 方法和构造函数 must be run on the AWT event dispatch thread,因此请更改您的 main 方法来做到这一点:

public static void main(String[] args) {
    EventQueue.invokeLater(() -> new EyePanel(600, 600));
}

您的代码与您声称的不完全一致(角膜/虹膜不在中心),但我认为您的问题是可以回答的。 Area 类可用于检查形状是否相交:

public void draw (Graphics g) {
    Graphics2D g2d = (Graphics2D) g;

    //eyelid
    g2d.setColor(Color.pink);
    g2d.fillOval(lidX, lidY, lidDiameter, lidDiameter);

    //sclera
    Area sclera = new Area(
        new Ellipse2D.Float(sclX, sclU, sclDiameter, sclB));
    g2d.setColor(Color.white);
    g2d.fill(sclera);

    g2d.setColor(Color.black);
    g2d.drawLine(sclX, sclC, sclX + sclDiameter, sclC);

    //cornea
    Area cornea = new Area(
        new Ellipse2D.Float(corX, corU, corDiameter, corB));
    Area hiddenCornea = (Area) cornea.clone();
    hiddenCornea.subtract(sclera);
    if (hiddenCornea.isEmpty()) {
        g2d.setColor(Color.cyan);
        g2d.fill(cornea);

        g2d.setColor(Color.red);
        g2d.drawLine(corX, corC, corX + corDiameter, corC);
    }
}

如果角膜的任何部分被隐藏(不与巩膜相交),这将跳过角膜的绘制。

【讨论】:

  • 谢谢!!这不仅有助于解决眼睑问题,还可以让角膜+瞳孔跟随鼠标,直到它到达巩膜的边界。
猜你喜欢
  • 1970-01-01
  • 2018-12-15
  • 2011-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-24
  • 2022-06-29
  • 1970-01-01
相关资源
最近更新 更多