粒子系统生成像素点验证码

Home / Android MrLee 2015-3-22 3029

最近在做一个rpg小游戏,研究到粒子系统。粒子系统(particle system)是图形里常用的特效。粒子系统可应用运动学模拟来做到很多不同的效果。粒子系统在游戏和动画中,常常会用来做雨点、火花、烟、爆炸等等不同的视觉效果。
粒子系统模拟大量的粒子,并通常用某些方法把粒子渲染。粒子通常有以下特性:
粒子是独立的,粒子之间互不影响(不碰撞、没有力) 粒子有生命周期,生命结束后会消失 粒子可以理解为空间的一个点,有时候也可以设定半径作为球体和环境碰撞 粒子带有运动状态,也有其他外观状态(例如颜色、影像等) 粒子可以只有线性运动,而不考虑旋转运动(也有例外) 下图是本人实现的一个酷酷的粒子效果(截图效果不太好,实际运行效果好很多)。

sample_thumb

上面的效果图,可以看到,我需要往画布上不断的添加白色的粒子(x坐标为随机值,y坐标为0,下降加速度为随机值),就和下雪一样。添加到画布上的粒子,会做向下类似于自由落体的加速运动,在运动过程中会遇到阻碍,就是在画面上文字区域内,当粒子碰到文字的时候,受到阻力,运动变得缓慢,这样粒子在有文字的地方不断的受到文字的阻碍,大量的白色粒子就会聚集到文字处,就形成了上面的粒子效果。实现代码如下:
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.PixelReader;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class SnowWord extends Application{
  private List snow = new LinkedList<>();
  double gravity = 0.15D;
  @Override
  public void start(Stage stage) throws Exception{
    WritableImage image = new WritableImage(500, 400);
    drawString(image, "东方上人", 60, 200);
    final PixelReader reader = image.getPixelReader();
    Canvas show = new Canvas(500, 400);
    final GraphicsContext context = show.getGraphicsContext2D();
    new AnimationTimer(){
      @Override
      public void handle(long arg0){
        context.clearRect(0, 0, 500, 400);
        context.setFill(Color.BLACK);
        context.fillRect(0, 0, 500, 400);
        context.setFill(Color.WHITE);
        Iterator it = snow.iterator();
        while(it.hasNext()){
          Point p = it.next();
          p.vy += gravity * p.s;
          p.y += p.vy;
          if(p.y >= 400){
            it.remove();
          }else{
            /* 指定坐标处是否处在文字上 */
            if(reader.getColor((int) p.x, (int) p.y).equals(Color.BLACK)){
              p.y -= p.vy;
              p.vy = 0;
              p.y += 0.2;
            }
            context.fillOval(p.x, p.y, 2, 2);
          }
        }
        for(int i = 0; i < 10; i++){
          snow.add(new Point(Math.random() * 500, 0, Math.random() + 0.5));
        }
      }
    }.start();
    Scene scene = new Scene(new Group(show));
    stage.setScene(scene);
    stage.setTitle("粒子系统 - www.zhouhaocheng.cn");
    stage.show();
  }
  public void drawString(WritableImage image, String text, int x, int y){
    BufferedImage buffer = SwingFXUtils.fromFXImage(image, null);
    Graphics g = buffer.getGraphics();
    g.setColor(java.awt.Color.BLACK);
    g.setFont(new Font("Microsoft YaHei", 1, 100));
    g.drawString(text, x, y);
    SwingFXUtils.toFXImage(buffer, image);
    g.dispose();
  }
  public static void main(String[] args){
    launch(args);
  }
  static class Point{
    double x; // x坐标
    double y; // y坐标
    double s; // 下降加速度
    double vy; // y轴方向速度
    public Point(double x, double y, double s){
      this.x = x;
      this.y = y;
      this.s = s;
      this.vy = 0;
    }
    public String toString(){
      return x + " , " + y + " , " + s + " , " + vy;
    }
  }
}

当然你可以发挥你的想象力,制作更有意思的粒子效果。记得以前看到国外有的网站用的那种全像素点的验证码,其实思路差不多。实现代码如下:
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Random;
public class NoisyCaptcha{
  // 图片的宽度。
  private int width = 120;
  // 图片的高度。
  private int height = 40;
  private String fontName;
  private int fontStyle = 1;
  private int fontSize;
  private static String codes = "abcdefghijkmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ23456789";
  public NoisyCaptcha(int width, int height){
    this(width, height, "Microsoft YaHei", 1, height - 10);
  }
  public NoisyCaptcha(int width, int height, String fontName, int fontStyle, int fontSize){
    this.width = width;
    this.height = height;
    this.fontName = fontName;
    this.fontStyle = fontStyle;
    this.fontSize = fontSize;
  }
  public BufferedImage genCode(String text){
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    Graphics2D g = image.createGraphics();
    g.setColor(Color.WHITE);
    g.fillRect(0, 0, width, height);
    g.setFont(new Font(fontName, fontStyle, fontSize));
    FontMetrics fm = g.getFontMetrics();
    g.setColor(Color.BLACK);
    g.drawString(text, width / 2 - fm.stringWidth(text) / 2, height / 2 + fm.getAscent() / 3);
    g.dispose();
    BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    g = result.createGraphics();
    g.setColor(Color.BLACK);
    g.fillRect(0, 0, width, height);
    g.setColor(Color.WHITE);
    for(int i = 0; i < width; i++){
      for(int j = 0; j < height; j++){
        double r = Math.random();
        /* 如下0.65和0.95可根据实际显示效果调整 */
        if(image.getRGB(i, j) == Color.BLACK.getRGB()){
          if(r > 0.65) g.drawOval(i, j, 1, 1);
        }else if(r > 0.95){
          g.drawOval(i, j, 1, 1);
        }
      }
    }
    g.dispose();
    return result;
  }
  
  public static String generateTextCode(int verifySize){
    int codesLen = codes.length();
    Random rand = new Random(System.currentTimeMillis());
    StringBuilder verifyCode = new StringBuilder(verifySize);
    for(int i = 0; i < verifySize; i++){
      verifyCode.append(codes.charAt(rand.nextInt(codesLen - 1)));
    }
    return verifyCode.toString();
  }
}
生成的验证码图片效果入下:

nosifycaptha16_thumb

本文链接:https://www.it72.com/1514.htm

推荐阅读
最新回复 (0)
返回