我正在尝试使用箭头键控制的可旋转线。当您单击鼠标时,一个球从光标上掉落,并在它到达该线时停止。
然而,球总是停在线的最高点,横跨一条平行于x轴的线。
我的文档类如下:
package
{
import flash.display.MovieClip;
import flash.events.*
import flash.display.Stage
import ball
public class Engine extends MovieClip
{
public static var stageRef:Stage
private static var leftKey:Boolean = false
private static var rightKey:Boolean = false
public static var pi = Math.PI
public static var lineRotate:Number = 0
public static var spinRate:Number = 60
public static var ground:line = new line()
public function Engine()
{
// constructor code
stage.addEventListener(Event.ENTER_FRAME, loop)
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler)
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler)
stage.addEventListener(MouseEvent.CLICK, addBall)
stageRef = stage
ground.x = 300
ground.y = 200
stage.addChild(ground)
}
private static function keyDownHandler(e:KeyboardEvent)
{
if (e.keyCode == 37) //left
{
leftKey = true
}
if (e.keyCode == 39)
{
rightKey = true
}
}
private static function keyUpHandler(e:KeyboardEvent)
{
if (e.keyCode == 37) //left
{
leftKey = false
}
if (e.keyCode == 39) //right
{
rightKey = false
}
}
public function loop(e:Event)
{
spin()
}
public static function addBall(e:MouseEvent) //adds ball
{
var tempBall:ball = new ball()
tempBall.x = e.stageX
tempBall.y = e.stageY
stageRef.addChild(tempBall)
}
private static function spin() //spins the "ground" line
{
if (leftKey) // minus
{
lineRotate -= spinRate
}
if (rightKey) // plus
{
lineRotate += spinRate
}
ground.rotation = lineRotate * (pi / 180) //convert to radians
}
}
}
球的等级如下:
package
{
import flash.display.MovieClip;
import flash.events.*
public class ball extends MovieClip
{
public var vX:Number = 0
public var vY:Number = 2
private var gravity:Number = 0
public function ball()
{
// constructor code
addEventListener(Event.ENTER_FRAME, loop)
}
public function loop(e:Event)
{
this.x += vX
this.y += vY
this.vY += gravity
if (this.x > stage.stageWidth || this.x < 0 || this.y < 0 || this.y > stage.stageHeight)
{
removeSelf()
}
if (Engine.ground.hitTestObject(this))
{
trace('yep')
stopBall()
}
else
{
trace('nope')
}
}
public function removeSelf()
{
removeEventListener(Event.ENTER_FRAME, loop)
this.parent.removeChild(this)
}
public function stopBall()
{
gravity = 0
vY = 0
vX = 0
}
}
}
我已将.swf上传到here.
答案 0 :(得分:2)
根据文章Collision detection methods: hit-test and hit-testobject alternatives,这是设计:
正如您所见,Flash使用了边界 盒子的对象 - 它需要 最高和最低点, 最左边和最右边的点和 在它们周围画一个矩形。
作者提到了几种替代方法来解决此限制,例如使用hitTestPoint或Grant Skinner的基于形状的碰撞检测。
答案 1 :(得分:2)
你可以做的最容易的事情是,对于球是一个hitTestPoint,第三个参数为true,它会打开形状检测。
ground.hitTestPoint(X,Y,TRUE);
好吧,嗯,你可以检查球上的一个点,就像它的底点一样,或者你可以检查球底部的一系列点以便更精确......这是最快的方法如果你没有计划任何比这更复杂的事情,请这样做。但是,如果你想创建一个完整的充实游戏,请将其留给像http://www.box2dflash.org/这样的二维物理库。
为了更大的游戏而忘记skinners碰撞检测(虽然这样的小东西可以存活下来),因为它是基于位图的并且会比box2D更能杀死性能,这是一个很好的掩码示例,但它不是一个好主意出于性能原因使用。
我已经改变了你的代码。我已经在球的底部发现了一堆积分,请记住,电影剪辑中球的0,0位于球中心的中心位置。
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.geom.Point;
public class ball extends MovieClip
{
public var vX:Number = 0;
public var vY:Number = 2;
private var gravity:Number = 0;
public function ball()
{
// constructor code
addEventListener(Event.ENTER_FRAME, loop);
}
public function loop(e:Event)
{
this.x += vX;
this.y += vY;
this.vY += gravity;
if (this.x > stage.stageWidth || this.x < 0 || this.y < 0 || this.y > stage.stageHeight)
{
removeSelf();
}
/*we will now check something like 18 points on the bottom side of the ball for colision
instead of just the bottom, you can probably guess why... if you cant, replace i on line
43 (var angleInRadians...) with 270 to test and then drop balls on a slopped ground surface... of course
you should definitely juse a physics engine like http://www.box2dflash.org/ for anything more complex.
*/
for (var i:int = 180; i<=360; i+=10)
{
/*keep in mind that ball.rotation property has 0 at the top of the ball, while here for these we are using the standard
Cartesian coordinate system. The effect of this on rotation would be that it is +90 and for X(yes, X) it would be Math.SIN(),
not Math.COS()!!!, and for Y it would be Math.sin() with a minus in front because of the flash coordinate system y axis rotation.
It's not really related to this, but it's a point that has anoyed me to no end in trig related stuff in flash when I was starting.
*/
var angleInRadians:Number = i / 180 * Math.PI;
var posX:Number = this.x + Math.round(Math.cos(angleInRadians) * width / 2);
var posY:Number = this.y - Math.round(Math.sin(angleInRadians) * height / 2);//minus because y in flash is upside down
Engine.ground.hitTestPoint(posX,posY, true);
if (Engine.ground.hitTestPoint(posX,posY, true))
{
stopBall();
}
else
{
}
}
/*if (Engine.ground.hitTestObject(this))
{
trace('yep')
stopBall()
}
else
{
trace('nope')
}*/
}
public function removeSelf()
{
removeEventListener(Event.ENTER_FRAME, loop);
this.parent.removeChild(this);
}
public function stopBall()
{
gravity = 0;
vY = 0;
vX = 0;
}
}
}
与上述无关,你需要重新考虑一下你的OOP,你做的事情有点不对劲:)。这个小项目可以应对的项目,但任何更大的项目都会让你头疼。不要把它当作攻击,我想尝试引导你走向“正确”的路径,并向你展示代码中的逻辑谬误,我没有提到这个“pwn”你导致你的oop很糟糕:)。
例如,重力,内部球?哎呀......如果你想让忍者,手里剑,布娃娃等有引力呢?你是否会将Ninjas从球类中分类出来?
<> Ninja延伸球?这应该很有趣。你认为重力的东西可能会有更好的地方吗? “重力”根本就是球的属性(错误,它本身就是这样,但不是这种均匀的引力你放在这里,它更像是一种渗透,所有现存的东西,因为有一些巨大的身体,我们太接近了)?它应该在引擎......
另外,你做了Engine.ground的事情......现在,这是一个静态变量......这是另一件坏事,非常糟糕的事情:)
原因类似于前面的例子,但有点转过身来。如果你想重新使用球,比如Engine2怎么办?还是Crytek引擎?还是UDK?我认为这可能是有问题的,你不觉得吗?你必须进去改变球类...想象一下,如果你使用的每一个代码都强迫你这样做......
基本上,你可能做过这样的事情:
var bla:ball = new ball(ground);
这样更好,更好......现在我们可以轻松地在crytek,udk和Engine2中使用它......
从技术上讲,您希望在代码中避免使用类似静态变量之类的东西,这种想法称为封装。我们的想法是,您可以将类的内部工作隐藏在与其无关或不应该了解的其他类中。您需要知道的越少,您的课程就越便携,可重复使用(yada yada)。 Engine.ground是一个巨大的封装断路器,因为球绝对不需要知道类引擎,它应该只关注对地面本身的引用......
随着时间的推移你将学习所有这些,编程中的模式,特别是哪些模式可以节省时间,哪些是令人震惊的,以及为什么(静态变量有它们的用途,但仅限于超简单的东西,如果是非常简单的东西,请避免使用Singletons你知道它们是什么吗。
http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)
对不起我给你带来的头痛......
请记住,使用物理引擎来处理更复杂的代码,不要重新发明轮子(为你的项目重用一切对他们有利/足够的东西)......测试这样的东西很有趣,但其他人在你之前做得更好,除非你特别需要深入研究他们的领域,否则你不需要关心每一个细节。你可能正在尝试建立游戏/东西,而不是打扰牛顿动力......
HitTest对于简单的东西来说很好,但这接近简单...... :)我们已经在这里略微进入了物理学,你可能会发现你需要一个更强大的解决方案......
一般来说,通过考虑类之间的封装和依赖关系,尝试使代码“健壮”。如果一个依赖感觉不自然(即球取决于引擎)那么某些东西可能是错误的,并且稍后会破坏,将会破坏另一个游戏或引擎或...我会在这里结束...
保重,玩得开心。