讲解 http://java.e800.com.cn/articles/2007/126/1169755227655353977_1.html
?
J2ME开发手机游戏物理模型之抛物线
物体做抛物线运动是游戏中基本运动物理模型之一! 在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));
??? }
}