2d游戏阴影动态生成技术在j2me中的实现

为了给2d游戏做出比较绚丽的效果,最近我真是煞费苦心啊,在3d中做出动态阴影比较好实现,2d中就比较难了,尤其是手机游戏中,要是给每个单位都加一张阴影贴图,容量就太过庞大了,所以应该要想一个比较好的算法能在游戏中动态生成阴影图,下面我给大家介绍一个在2d桌面游戏动态生成阴影的算法,并将它用j2me实现,最终效果如图:
    要实现一个阴影首先要了解阴影的特点,当阳光照射到物体表面时,会投影出一个当前物体外观轮廓类似份的黑影,而这个黑影多半又是倾斜的,且是半透明的,并不会完全覆盖地表使之成为一团黑色,那么算法由此就可以得出。
生成阴影的步骤是:
1,将当前动作的原图不透明部分全部变黑
2,将变黑后的图片纵向缩小50%
3,将缩小后的图片倾斜45度
4,半透明黑色的部分
其中每一步都涉及一个比较复杂的算法
下面将挨着讲解每一步的实现,
首先,将动作原图不透明的部分全部变黑,需要操作png图片rgb数组,
使图片的不透明rgb值全部等于0,实现函数如下:

public Image effect_black(Image src) {
        int srcW = src.getWidth();
        int srcH = src.getHeight();
        int[] srcPixels = getPixels(src);
        int r = 0;
        int g = 0;
        int b = 0;
        int a = 0;
        int argb;
        for (int i = 0; i < srcH; i++) {
            for (int ii = 0; ii < srcW; ii++) {
                argb = srcPixels[i * srcW + ii];
                a = ((argb & 0xff000000) >> 24); // alpha channel
                r = ((argb & 0x00ff0000) >> 16); // red channel
                g = ((argb & 0x0000ff00) >> 8); // green channel
                b = (argb & 0x000000ff); // blue channel
                if (r != 0) {
                    r = 0;
                }
                if (g != 0) {
                    g = 0;
                }
                if (b != 0) {
                    b = 0;
                }
                srcPixels[i * srcW + ii] = ((a << 24) | (r << 16) | (g << 8) | b);
            }
        }
        return drawPixels(srcPixels, srcW, srcH);
    }

第二步,将变黑图片纵向缩小50%
其实也不一定是50%,你可以想象清晨和傍晚的影子是最长的,而中午几乎是个脚下的圈,因此要根据你所设定的游戏发生时间来决定,甚至可以让影子的长度动态改变,可以和以前我帖子中介绍过的昼夜系统结合,较好的模拟真实环境,实现函数如下:

    /*
     * 纵向调整图片大小,注意参数1~10时会放大
     * n 缩放比例
     */

    public Image effect_resizeImageH(Image src, int n) {
        if (n == 0) {
            n = 10;
        }
        int srcW = src.getWidth();
        int srcH = src.getHeight();
        int destH = srcH * 10 / n;
        int destW = srcW;
        int[] destPixels = new int[destW * destH];
        int[] srcPixels = getPixels(src);
        for (int destY = 0; destY < destH; ++destY) {
            for (int destX = 0; destX < destW; ++destX) {
                int srcX = (destX * srcW) / destW;
                int srcY = (destY * srcH) / destH;
                destPixels[destX + destY * destW] = srcPixels[srcX + srcY * srcW];
            }
        }
        return drawPixels(destPixels, destW, destH);
    }

第三步,将图片倾斜45度

这点是算法最复杂的部分
因为sprite类本身只能进行90度的整数倍数的旋转,因此要实现任意角度的旋转同样需要我们操作png的像素

其基本的原理是

假设,P(x,y)旋转t角度后,得到P’(x’,y’),P与P’之间的关系如下:

(x’,y’) = (x cos(t) + y sin(t),y cos(t) - x sin(t))下面采用minisoyou的bb大侠的算法,它的算法旋转后比其他算法失真较小,实现的代码如下
/** 透明 **/
    public static int TRANSPARENT = 0;
    /** 不透明 **/
    public static int OPAQUE = 15;
    //任意角度翻转,注意角度是弧度值

    public Image rotateAny(Image src, double _angle) {
        int i, j;
        int[] _pixels = getPixels(src);
        int _width = src.getWidth();
        int _height = src.getHeight();
        double radius = Math.sqrt(_width * _width + _height * _height);
        int r = (int) radius;
        int[] newPixels = new int[r * r];
        for (i = 0; i < newPixels.length; i++) {
            newPixels = (TRANSPARENT) << 24;
//            newPixels = 0x00ffffff;
        }
        double x2, y2;
        int x3, y3;
        double cos = Math.cos(_angle);
        double sin = Math.sin(_angle);
        for (i = 0; i < r; i++) {
            x2 = (-r / 2) * cos + (i - r / 2) * sin;
            y2 = (r / 2) * sin + (i - r / 2) * cos;
            x3 = (int) x2;
            y3 = (int) y2;
            for (j = 0; j < r; j++) {
                if (x3 >= -_width / 2 && x3 < _width / 2 && y3 >= -_height / 2 && y3 < _height / 2) {
                    newPixels[i * r + j] = _pixels[(y3 + _height / 2) * _width + x3 + _width / 2];
                }
                x2 += cos;
                y2 -= sin;
                x3 = (int) x2;
                y3 = (int) y2;
            }
        }
        return drawPixels(newPixels, r, r);
    }
最后,半透明黑色的部分


注意是只半透明黑色部分,则需要判断png中的每个像素的透明度

实现代码如下:

/**     *     * @param img     *            原始图片     * @param transparent     *            透明度 0-255之间     * 越大越不透明,只半透明黑色部分     * @return 处理透明度后的图片     */    public Image effect_transparent_black(Image img, int transparent) {        if (transparent < 0 || transparent > 255) {            return img;        }        int srcW = img.getWidth();        int srcH = img.getHeight();        int[] srcPixels = getPixels(img); //函数功能 讲图片数据存入指定数组        int r = 0;        int g = 0;        int b = 0;        int a = 0;        int argb;        for (int i = 0; i < srcH; i++) {            for (int ii = 0; ii < srcW; ii++) {                argb = srcPixels[i * srcW + ii];                a = ((argb & 0xff000000) >> 24); // alpha channel                r = ((argb & 0x00ff0000) >> 16); // red channel                g = ((argb & 0x0000ff00) >> 8); // green channel                b = (argb & 0x000000ff); // blue channel                if (argb == 0xff000000) {                    srcPixels[i * srcW + ii] = ((transparent << 24) | (r << 16) | (g << 8) | b);                } else {                    srcPixels[i * srcW + ii] = 0x00ffffff;                }            }        }        return drawPixels(srcPixels, srcW, srcH); //将数组转化为图片    }


最后你在绘制时需要注意,需要先绘制阴影再绘制人物或建筑,毕竟,影子是从脚下“长“出来的,而不是头上
希望大家支持~~(转自 hustGame)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值