แฟ้มประวัติSunwing's note bookรูปถ่ายบล็อกรายการ เครื่องมือ วิธีใช้

บล็อก


23 ธันวาคม

碰撞检测——矩形重叠碰撞测试,线段相交碰撞测试,线段交点

    // rectangle hit test
    public static boolean rectHitTest(int x1, int y1, int x2, int y2, int x3,
            int y3, int x4, int y4) {
        if (Math.max(x1, x2) < Math.min(x3, x4)
                || Math.max(y1, y2) < Math.min(y3, y4)
                || Math.min(x1, x2) > Math.max(x3, x4)
                || Math.min(y1, y2) > Math.max(y3, y4)) {
            return false;
        }
        return true;
    }
    // segment hit test
    public static boolean segmentHitTest(int x1, int y1, int x2, int y2,
            int x3, int y3, int x4, int y4) {
        // fast hit test
        if (!rectHitTest(x1, y1, x2, y2, x3, y3, x4, y4)) {
            return false;
        }
        // segment hit test judgement
        /**/
        if (vectorProduct(x1 - x3, y1 - y3, x4 - x3, y4 - y3)
                * vectorProduct(x2 - x3, y2 - y3, x4 - x3, y4 - y3) <= 0
            && vectorProduct(x3 - x1, y3 - y1, x2 - x1, y2 - y1)
                * vectorProduct(x4 - x1, y4 - y1, x2 - x1, y2 - y1) <= 0) {
            return true;
        }
        /**/
        return false;
    }
    /**
     *
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     * @param x3
     * @param y3
     * @param x4
     * @param y4
     * @return int array
     *         if return null, then the two segments are not crossed
     *         if return array.length = 2, then segments are crossed at x=array[0], y=array[1]
     *         if return array.length = 4, then segments are overlaped from
     *         coordinate (array[0],array[1]) to (array[2], array[3])
     *         if return else then means error
     */
    public static int[] segmentHitPoint(int x1, int y1, int x2, int y2, int x3,
            int y3, int x4, int y4) {
        if (!segmentHitTest(x1, y1, x2, y2, x3, y3, x4, y4))
            return null;
        int k1, a1, k2, a2, x, y;
        int mathShift = 10;
        // on the same vertical line
        if (x1 == x2 && x3 == x4 && x1 == x2) {
            int maxY = Math.max(Math.max(y1, y2), Math.max(y3, y4));
            int minY = Math.min(Math.min(y1, y2), Math.min(y3, y4));
            int[] arrayY = new int[] { y1, y2, y3, y4 };
            int[] result = new int[] { x1, 0, x1, 0 };
            int index = 1, i = 0;
            while (i < 4 && index < 4) {
                if (arrayY[i] != maxY && arrayY[i] != minY) {
                    result[index] = arrayY[i];
                    index += 2;
                }
                i++;
            }
            return result;
        } else if (x1 == x2) {
            k2 = (y3 - y4 << mathShift) / (x3 - x4);
            a2 = y3 - (k2 * x3 >> mathShift);
            x = x1;
            y = (x * k2 >> mathShift) + a2;
        } else if (x3 == x4) {
            k1 = (y1 - y2 << mathShift) / (x1 - x2);
            a1 = y1 - (k1 * x1 >> mathShift);
            x = x3;
            y = (x * k1 >> mathShift) + a1;
        }
        // normal state
        else {
            k1 = (y1 - y2 << mathShift) / (x1 - x2);
            k2 = (y3 - y4 << mathShift) / (x3 - x4);
            if (k1 == k2) {
                int maxX = Math.max(Math.max(x1, x2), Math.max(x3, x4));
                int minX = Math.min(Math.min(x1, x2), Math.min(x3, x4));
                int[] arrayX = new int[] { x1, x2, x3, x4 };
                int[] arrayY = new int[] { y1, y2, y3, y4 };
                int[] result = new int[4];
                int index = 0, i = 0;
                while (i < 4 && index < 4) {
                    if (arrayX[i] != maxX && arrayX[i] != minX) {
                        result[index++] = arrayX[i];
                        result[index++] = arrayY[i];
                    }
                    i++;
                }
                return result;
            }
            a1 = y1 - (k1 * x1 >> mathShift);
            a2 = y3 - (k2 * x3 >> mathShift);
            x = (a2 - a1 << mathShift) / (k1 - k2);
            y = (x * k1 >> mathShift) + a1;
        }
        return new int[] { x, y };
    }
    // get the vector product
    private static int vectorProduct(int x1, int y1, int x2, int y2) {
        return x1 * y2 - x2 * y1;
    }
19 ธันวาคม

策划学习笔记——sid meier 语录

先考虑类型,然后再考虑游戏主题是十分危险的。
首先要确定游戏主题,然后找到合理的方式和适当的风格来制作。
 
Civilization 有一种神奇的吸引力,这并不出自策划本身。任何自然结合的事物都具备这种特质。Civilization 的成功是由于各部分协调一致的结果。(你个样好唔自然~)
 
让玩家用自己的知识来玩游戏。可以在游戏中应用自己的知识时,玩家会变得有自信。
 
如果趣味性和历史发生冲突,我们要服从趣味性。(可悲的历史...)
 
游戏可以分成3类:分别是设计者可以获得所有乐趣的游戏,AI可以获得所有乐趣的游戏,玩家可以获得所有乐趣的游戏。(好似AI可以获得所有乐趣的游戏好多...)
 
我们的原则是,尽可能让玩家有更多的选择。
 
 
13 ธันวาคม

游戏策划学习笔记--玩家的需要

一、玩游戏的理由
    1、挑战
         所有游戏都必须具备挑战。
    2、交流
    3、独处的需要(译文是“独处的经历”)
         与AI交流比与人交流省力,玩家需要私人的休息空间。
    4、炫耀
    5、情感体验
    6、幻想
    我的想法:设计得好的游戏不一定要涵括以上所有理由,而要针对某个理由将游戏特色发挥到极至。
                   也就是说要清楚游戏面向什么市场,并有效地坚持下来。
                   但是任何游戏必须具备挑战,这是做游戏的基本条件。
 
二、满足玩家的期望
     1、由动作所产生的结果需要可预知性。无论失败或成功都需要清晰的原因
     2、在同一个游戏的进行过程中,不要突然往其中插入与原游戏完全不相符的机制和规则。
     3、预测玩家在游戏世界中会做些什么,并保证玩家尝试这些动作的时候会发生合乎情理的事情。
     4、游戏需要一个目标,并且要让玩家清晰地了解该目标。
     我的想法:对于大型游戏,目标需要有一定的吸引力。对于休闲类游戏,则不是太重要。
     5、快速给予奖励,使玩家高昂的情绪不至于很快地消退,甚至觉得沮丧。
     我的想法:对于策略类的游戏,第一次小奖励要在30分钟内给予,动作游戏和休闲游戏需要在1分钟内给予。
     何谓小奖励?连击,连串动作并成功越过难关,组合按键发出的技能,致命一击等等。小奖励通常都伴随着华丽的声光效果,以带给玩家视听冲击。例如画面上跳跃出的 XX HIT, 冲击性大字体显示的致命一击的伤害,华丽而流畅的组合技。甚至只是表现出一气呵成的动作,就已经能带给玩家极大的满足感。
     6、连续地让玩家沉浸于幻想世界,任何bug或者主角与玩家设想不一致的行为,都会打断玩家的幻想。
     7、挑战性。游戏在一开始应该简单,但在游戏中期应该让玩家尝试失败,并且应该让玩家意识到,越过难关后会有更吸引的奖励。当然,如果没有,玩家会觉得沮丧。
     8、游戏应该存在多种合理方式暗算玩家,一成不变只会让游戏失去吸引力。
     9、自动存档
     10、游戏不能存在一些无法跨越的障碍。
     11、片头动画虽然吸引,但还是游戏本身更吸引。
     12、玩家不知道他们要的是什么,但是他们知道什么是他们要的
05 ธันวาคม

particle system

粒子运动系统概述

 

(以下某些言论其实已经颇为过时,事实上粒子系统所产生的效果不如预期,所以各位应该着眼于运动这一部分。可以先看看www.gameres.com上面的相关文章。注意,我所讨论的是j2me。感谢我高中的物理老师司徒美仙)

 

 

一、粒子运动系统目的

     实现与游戏世界无联系的物体运动。

 

二、粒子运动系统接口

     1. 构造粒子

         传入粒子的初始化数据,粒子会按照初始化数据作运动直到消亡,过程中无法对其轨迹作出任何影响。

     2. 粒子运动

         每帧调用运动接口,使粒子每帧作出运动。

     3. 粒子显示

         调用粒子显示接口,在屏幕上画出粒子。

 

三、运动的实质(参考高中物理学,微积分,参数方程等相关知识)

     1. 运动的叠加

         运动系统的基础。要描述一个在2D平面乃至3D空间中的运动,是颇为复杂的事。为了让问题简化,我们必须首先将运动分解。如果是2D平面的运动,则分解成x和y两个坐标轴上的运动叠加。这两个运动是相互无影响的。(参阅初中物理学课本,运动、力的分解)

 

     2. 环境状态和初始状态

         a) 环境状态:引力,弹力,风,阻力等

             这些都是影响运动的因素,都是力,因为粒子无质量,所以在系统中直接以加速度表示。通常有:

             阻尼系数p,无方向,阻力加速度 = -速度×阻尼系数。 如果环境是各向异性的,可以分别设定xy方向上的阻尼系数。如果阻力只与速度方向有关,则 阻力加速度 = -(|速度|/速度)×系数

             平衡点,弹性势能为0的点。

             弹性系数k,无方向,弹力加速度 = -相对于平衡点的位移×弹性系数,这里是把质量的因素整合到系数中考虑了。

             其他力,包括重力。先自行把各个恒力合成,换算出xy上的加速度。

 

         b) 初始状态:初速,初始加速度,起始坐标,生命周期

 

     3. 运动的逻辑运算

         在实际使用中,我们只关心某个时刻粒子的位置。但是运动是具有连续性的,因此可以通过上一时刻的位置计算出下一时刻的位置。

         a) 匀速直线运动

             无环境状态,运动全过程无力作用

             速度 v

             初位移 s0

             则 s1 = s0 + v

 

         b) 自由落体运动, 平抛运动, 斜抛运动 和 竖直上抛运动

             ————环境————

             重力加速度 g = ay

             ————初始————

             初速度 vx0 vy0

             初位移 x0 y0

             ————计算————

             则:

             x1 = x0 + vx0

             y1 = y0 + vy0

             // 为再下一时刻计算

             vx1 = vx0

             vy1 = vy0 + g

             (做做看,x y上的两个竖直上抛运动的叠加,即有ax,ay,很有型的)

             

          c) 简谐振动,正弦波动 和 圆周运动

              ————环境————

             平衡点 Px Py

             弹性系数 kx ky

             无其他环境影响

              ————初始————

             初始加速度 ax0 ay0

             初速度 vx0 vy0

             初位移 x0 y0

             ————计算————

             则:

             x1 = x0 + vx0

             y1 = y0 + vy0

             // 为再下一时刻计算

             vx1 = vx0 + ax0

             vy1 = vy0 + ay0

             ax1 = - (x1 - Px) × kx =(Px - x1) × kx

             ay1 = - (y1 - Py) × ky =(Py - y1) × ky

 

            

             为何简谐振动和圆周运动都是同样的算法?

             因为实际上圆周运动就是由xy轴上,两个相位相差90度的简谐振动所合成。只要设置不同的初始状态,就可以得到不同的运动。

             另外,只要在平衡点产生一个运动,就可以得到更复杂的运动了。

             (叠加 n 个简谐振动会怎样呢? 呵呵,没试过)

 

         d) 其他运动

             计算流程都是一样的。

             先通过已知的上一时刻速度计算下一时刻的  x y 坐标

             再通过上一时刻的加速度计算下一时刻的 速度

             然后是计算下一时刻的 加速度

            

             所有的计算基本上都是+-法,因此速度是十分快的。这也是采取这种运动计算方法的优势所在。

 

控制对象

这里,控制对象的“控制”是形容词而非动词。
 
1、控制对象的由来
     在程序模块化的过程中,最常见的一个情况是:进入某个系统并退出后,程序的逻辑改变。而我们要讨论的问题是:如何低耦合地实现?我的结论是——控制对象。
 
2、控制对象的使用
     以《战国》的窗口系统为例。
     窗口系统的出现,是由于源程序中严重的重用性不足,导致代码量过长以及难以想象的复杂度。窗口系统简化了关于窗口部分的画图代码,简化了窗口控制流程,但是对于逻辑上的耦合一直是个非常大的问题。一些新窗口的创建,选项导致的主程序逻辑跳转等等,通通都在该系统中实现。因此它严格上来说还不能算是一个系统模块,高耦合使名义上的窗口不能剥离为其他程序所用。
 
     如何使其独立出来?
 
     其实耦合的程序都可以看成是一段段子程序,在系统外执行,只是由于全局变量的方便使用而写到系统中。
 
     首先,主程序需要标记去判断应该执行什么子程序。这些标记就是控制对象。
    
     其次,系统中不应该对控制对象进行任何处理。控制对象应该原封不动地送还主程序。
     在窗口系统中,所有的控制跳转都是由于确定键按下所触发的。所以窗口系统送还控制对象的通道就是按键接口。如果送还null则表示无对应的控制对象。
 
     最后,在构建窗口时传入控制对象列表与每个窗口选项相对应。
 
     in a word,使用控制对象的方法就是不使用。控制对象是用于主程序对全局的判断,而不是独立系统应该去处理的。