讲解 http://java.e800.com.cn/articles/2007/126/1169755227655353977_1.html
物体做抛物线运动是游戏中基本运动物理模型之一! 在PC游戏中可以由重力公式轻易模拟,但在手机游戏中 ,由于多数手机不支持浮点运算因此不能用sin ,cos,来分解初速度。所以只能用近似模拟的方法!我所采用的是:先放大后缩小的模拟方式,并且为了更精确加入了一定的偏移量。
先用哈希表列出0-90度的正弦值,并且把值放大100000倍,例如:
Hashtable anglevalue; public void loadAnglevalue() { anglevalue = new Hashtable(); anglevalue.put(String.valueOf(0),new Integer(0)); anglevalue.put(String.valueOf(30),newInteger(50000)); anglevalue.put(String.valueOf(60),new Integer(86603)); anglevalue.put(String.valueOf(90),new Integer(100000)); …… } |
这样就可以得出各种角度的正余弦值。
设初速度为V0 物体当前坐标为x=0,y=0; t为时间 g重力=10;
根剧力学公式
Vx=V0*cos&; Vy=V0*sin&; |
再根据重力公式:
x=Vx*t; y=Vy*t –5*t*t; |
由于cos& sin&都是放大了100000倍的所以 再得到手机屏幕坐标的时候应该缩小100000倍
x=Vx*t/100000; y=(Vy*t –5*t*t)/100000; |
现在公式中除了t之外都解决了! 现在来解决时间t;
我们可以在游戏主循环的 中有不断增加t的值 但是因为主循环非常快!以毫秒计算,所以我们应该加入缓冲:
while (true){ thisThread.sleep(10); if(bFire){ tTemp++; if (tTemp >10) { t+=1; tTemp = 0; } } |
代 码中的if (tTemp >10) 这个值的判断就调整了时间的增长频率!你也可以用if (tTemp >2)来使时间增长加快 或则用其他数值让时间变慢。注意的一点就是我们的时间也要放大!至于放大多少倍则要看游戏的节奏!我这里暂且放大 20000倍,因此公式为:
x=Vx*t/100000; y=(Vy*t –5*t*t*20000)/100000; |
还有我们需要把 物体初始位置放在 屏幕的下放那就需要加个初始位置常量,公式变为:
x=Vx*t/100000; y=(100000*(getHeight()-20))-(Vy*t –5*t*t*20000)/100000; |
getHeight()在手机中为得到手机屏幕的高度。好了,来看看用了这个公式后的运行效果(NOKIA 7650模拟器 或则uniJava模拟器)
图1 |
这是45度角情况下的抛物线轨迹。
是不是觉得高度不够呢!运算不够精确!那么我们在Y上加个偏移量来增加高度,公式改为:
x= (vx+windSpeed )*t /100000; ; int pianyi=(t*400000); if(vy==0){ pianyi=0; } y=(100000*(getHeight()-imgWu.getHeight())-(vy*t-100000*t*t+pianyi))/100000; |
这里的X轴还加了风速 windSpeed 现实中物体定受风速影响!当然这里的风速也是放大的了;
if(vy==0){ pianyi=0; } |
这个代码是在平抛的时候就不需要加入高度偏移了。现在再看45度角的 抛物线
图2 |
如果你还不满意还可以改动偏移数值来让模拟更精确。下面来看一些角度在不同力度和风速下的轨迹快照:
|
|
package paowuxian;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
/**
* <p>Title: </p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2005</p>
* <p>Company: </p>
* @author not attributable
* @version 1.0
*/
public class MIDlet1 extends MIDlet {
static MIDlet1 instance;
Displayable1 displayable = new Displayable1();
public MIDlet1() {
instance = this;
}
public void startApp() {
Display.getDisplay(this).setCurrent(displayable);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public static void quitApp() {
instance.destroyApp(true);
instance.notifyDestroyed();
instance = null;
}
}
package paowuxian;
import javax.microedition.lcdui.*;
import java.io.*;
import java.util.Hashtable;
/**
* <p>
* Title:
* </p>
* <p>
* Description:
* </p>
* <p>
* Copyright: Copyright (c) 2005
* </p>
* <p>
* Company:
* </p>
*
* @author not attributable
* @version 1.0
*/
public class Displayable1 extends Canvas implements Runnable {
private Image imgWu = null;
private int x, y;
private boolean bFire = false;
Thread thisThread;
private int angle = 45;
private int v0 = 8;
private boolean bShowline = true;
private int t;
private static Hashtable angleValue;
public Displayable1() {
// loadAngleValue();
try {
imgWu = Image.createImage("/images/paodan.png");
y = getHeight() - 8;
} catch (IOException ex) {
}
thisThread = new Thread(this);
thisThread.start();
}
private static int[] getPostion(int _v0, int t, int _angle) {
int vx = getCosAngleValue(_angle) * _v0;
int vy = getSinAngleValue(_angle) * _v0;
int dX = vx / 100000;
int dY = -(vy - 100000 * t) / 100000;
return new int[] { dX, dY };
}
private void gameRun() {
if (bFire) {
int[] pos = getPostion(v0, t, angle);
System.out.println(pos[0]+""+" "+pos[1]);
x += pos[0];
y+= pos[1];
}
repaint();
}
protected void paint(Graphics g) {
g.setColor(0xffffffff);
g.fillRect(50, 10, 80, 40);
if (bShowline) {
g.setColor(0xffffffff);
g.fillRect(0, 0, getWidth(), getHeight());
}
g.setColor(0x0000ff);
g.drawString("角度" + angle + "(按8/2键调整)", 50, 0, 0);
g.drawString("力度" + v0 + "(按1/4)", 50, 10, 0);
g.drawString("是否留下轨迹" + (bShowline ? " 否" : " 是") + "(按3)", 50, 20, 0);
// g.drawString("风力" + windSpeed / 100000 + "(按7/9)", 50, 30, 0);
g.drawString("按5发射",50,30,0);
g.drawImage(imgWu, x, y, 0);
}
public void run() {
while (true) {
try {
thisThread.sleep(10);
if (bFire) {
t += 1;
if (y > getHeight() || x > getWidth()) {
x = 0;
y = getHeight() - 8;
bFire = false;
t = 0;
}
}
} catch (InterruptedException ex) {
}
gameRun();
}
}
/**
* keyPressed
*
* @param keyCode
* int
* @todo Implement this javax.microedition.lcdui.Canvas method
*/
protected void keyPressed(int keyCode) {
if (keyCode == KEY_NUM5) {
bFire = true;
// vx = Resource.getCosAngleValue(angle) * v0;
// vy = Resource.getSinAngleValue(angle) * v0;
} else if (keyCode == KEY_NUM8) {
if (angle > 0) {
angle -= 3;
}
} else if (keyCode == KEY_NUM2) {
if (angle < 90) {
angle += 3;
}
} else if (keyCode == KEY_NUM1) {
v0++;
} else if (keyCode == KEY_NUM4) {
v0--;
} else if (keyCode == KEY_NUM3) {
bShowline = !bShowline;
}
// else if (keyCode == KEY_NUM7) {
// windSpeed += 100000;
// } else if (keyCode == KEY_NUM9) {
// windSpeed -= 100000;
// }
}
/**放大了10000倍的角度值*/
static {
angleValue = new Hashtable();
angleValue.put(String.valueOf(0), new Integer(0));
angleValue.put(String.valueOf(3), new Integer(5236));
angleValue.put(String.valueOf(6), new Integer(10453));
angleValue.put(String.valueOf(9), new Integer(15643));
angleValue.put(String.valueOf(12), new Integer(20791));
angleValue.put(String.valueOf(15), new Integer(25882));
angleValue.put(String.valueOf(18), new Integer(30902));
angleValue.put(String.valueOf(21), new Integer(35837));
angleValue.put(String.valueOf(24), new Integer(40674));
angleValue.put(String.valueOf(27), new Integer(45400));
angleValue.put(String.valueOf(30), new Integer(50000));
angleValue.put(String.valueOf(33), new Integer(54464));
angleValue.put(String.valueOf(36), new Integer(58779));
angleValue.put(String.valueOf(39), new Integer(62932));
angleValue.put(String.valueOf(42), new Integer(66913));
angleValue.put(String.valueOf(45), new Integer(70711));
angleValue.put(String.valueOf(48), new Integer(74314));
angleValue.put(String.valueOf(51), new Integer(77715));
angleValue.put(String.valueOf(54), new Integer(80902));
angleValue.put(String.valueOf(57), new Integer(83867));
angleValue.put(String.valueOf(60), new Integer(86603));
angleValue.put(String.valueOf(63), new Integer(89101));
angleValue.put(String.valueOf(66), new Integer(91355));
angleValue.put(String.valueOf(69), new Integer(93358));
angleValue.put(String.valueOf(72), new Integer(95106));
angleValue.put(String.valueOf(75), new Integer(96593));
angleValue.put(String.valueOf(78), new Integer(97815));
angleValue.put(String.valueOf(81), new Integer(98769));
angleValue.put(String.valueOf(84), new Integer(99452));
angleValue.put(String.valueOf(87), new Integer(99863));
angleValue.put(String.valueOf(90), new Integer(100000));
}
public static int getSinAngleValue(int angle) {
int tempAngle = (angle > 90 ? (180 - angle) : angle);
int tempValue = ((Integer) (angleValue.get(String.valueOf(tempAngle))))
.intValue();
return tempValue;
}
public static int getCosAngleValue(int angle) {
int tempAngle = (angle > 90 ? angle - 90 : 90 - angle);
int tempValue = ((Integer) (angleValue.get(String.valueOf(tempAngle))))
.intValue();
return (angle <= 90 ? tempValue : (-tempValue));
}
}