[我道歉,如果这不是一个非常深入的问题,但我想一劳永逸地解决这个问题]
我试图查看四叉树,但在没有任何优化正常工作的情况下遇到碰撞检测时遇到了麻烦。做了搜索,发现了一个非常简洁的例子: http://wonderfl.net/c/kyLx (主要是onenterframeC部分)
试图模仿这一点,它将无法正常工作。 在特定对象之间仅检测到一些碰撞。当物体不移动时,由于某种原因,它似乎工作得更好。
我真的无法弄清楚问题是什么,代码与示例基本相同。我没有盲目复制粘贴它,我理解发生了什么,除了这一部分:
if (j <= i)
continue;
我永远不会变得更大吗?该线也完全消除了我的任何工作碰撞。
这是我做的: [查看结果:http://martinowullems.com/collision.swf
主要课程
package
{
import com.martino.objects.Square;
import com.martino.world.TestWorld;
import flash.display.MovieClip;
import flash.events.Event;
import net.hires.debug.Stats;
/**
* ...
* @author Martino Wullems
*/
public class CollisionTest extends MovieClip
{
var world:TestWorld;
public function CollisionTest()
{
addEventListener(Event.ADDED_TO_STAGE, onStage);
}
private function onStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onStage);
SetupWorld();
addChild(new Stats());
}
private function SetupWorld():void
{
world = new TestWorld();
addChild(world);
addObjects(50);
}
private function addObjects(amount:int):void
{
for (var i:int = 0; i < amount; ++i) {
var square:Square = new Square(14);
world.addObject(square);
square.x = Math.random() * stage.stageWidth;
square.y = Math.random() * stage.stageHeight;
square.speedX = (Math.random() * 1) + 1;
square.speedY = (Math.random() * 1) + 1;
}
}
}
}
TestWorld
package com.martino.world
{
import com.martino.objects.Ball;
import com.martino.objects.CollisionObject;
import flash.display.MovieClip;
import flash.events.Event;
/**
* ...
* @author Martino Wullems
*/
public class TestWorld extends MovieClip
{
public var objects:Array;
public function TestWorld()
{
initWorld();
}
private function initWorld():void
{
objects = new Array();
addEventListener(Event.ENTER_FRAME, loopWorld);
}
private function loopWorld(e:Event):void
{
for (var i:int = 0; i < objects.length; i++) {
MoveObject(objects[i]);
CheckCollision(i, objects[i]);
}
}
private function CheckCollision(i:int, object:CollisionObject):void
{
//for (var j:int = i + 1; i < objects.length; j++) {
for (var j:int = 0; j < objects.length; j++) {
//if (j <= i)
//continue;
var objectB:CollisionObject = objects[j];
//hittest
if (object.hitTestObject(objectB)) {
object.isHit = true;
objectB.isHit = true;
}else {
object.isHit = false;
objectB.isHit = false;
}
/////////////////
// CHECK X Y //
////////////////
/*if (object.x + object.width < objectB.x) {
} else if (object.x > objectB.x + objectB.width) {
object.isHit = objectB.isHit = false;
} else if (object.y + object.height < objectB.y) {
object.isHit = objectB.isHit = false;
} else if (object.y > objectB.y + objectB.height) {
object.isHit = objectB.isHit = false;
} else {
object.isHit = objectB.isHit = true;
}*/
object.debugDraw();
objectB.debugDraw();
}
}
private function MoveObject(object:CollisionObject):void
{
object.x += object.speedX;
object.y += object.speedY;
////////////////////
//check boundaries//
////////////////////
if (object.x > stage.stageWidth)
{
object.speedX *= -1;
}else if (object.x < 0)
{
object.speedX *= -1;
}else if (object.y > stage.stageHeight)
{
object.speedY *= -1;
}else if (object.y < 0)
{
object.speedY *= -1;
}
}
public function addObject(object:CollisionObject):void
{
objects.push(object);
addChild(object);
}
}
}
CollisionObject
package com.martino.objects
{
import flash.display.Sprite;
import flash.events.MouseEvent;
/**
* ...
* @author Martino Wullems
*/
public class CollisionObject extends Sprite
{
public var size:int;
public var speedX:int = 0;
public var speedY:int = 0;
public var graphic:Sprite;
var sleeping:Boolean = false;
public var isHit:Boolean = false;
public function CollisionObject()
{
addEventListener(MouseEvent.MOUSE_DOWN, grab);
addEventListener(MouseEvent.MOUSE_UP, letGo);
}
private function grab(e:MouseEvent):void
{
startDrag();
speedX = 0;
speedY = 0;
}
private function letGo(e:MouseEvent):void
{
stopDrag();
}
public function Collision():void{
}
//////////////////////
// setter and getter//
//////////////////////
public function set isHit(value:Boolean):void {
_isHit = value;
graphic.visible = _isHit;
hitGraphic.visible = !_isHit;
}
public function get isHit():Boolean {
return _isHit;
}
}
}
方
package com.martino.objects
{
import flash.display.Sprite;
/**
* ...
* @author Martino Wullems
*/
public class Square extends CollisionObject
{
public var hitGraphic:Sprite;
public function Square(Size:int)
{
size = Size;
drawSquare();
}
private function drawSquare():void
{
graphic = new Sprite();
graphic.graphics.beginFill(0xFF0000);
graphic.graphics.drawRect(0, 0, size, size);
graphic.graphics.endFill();
addChild(graphic);
hitGraphic = new Sprite();
hitGraphic.graphics.beginFill(0x0066FF);
hitGraphic.graphics.drawRect(0, 0, size, size);
hitGraphic.graphics.endFill();
addChild(hitGraphic);
hitGraphic.visible = false;
}
override public function Collision():void {
trace("I collided with a friend (inside joke)");
}
public override function debugDraw():void {
if (isHit) {
graphic.visible = false;
hitGraphic.visible = true;
}else {
graphic.visible = true;
hitGraphic.visible = false;
}
}
}
}
非常感谢任何帮助,希望进一步了解这一点!
编辑:更改了一些内容,有进展但我还不清楚其他内容!
改变了TestWorld.as中的一些内容:
package com.martino.world
{
import com.martino.objects.Ball;
import com.martino.objects.CollisionObject;
import flash.display.MovieClip;
import flash.events.Event;
/**
* ...
* @author Martino Wullems
*/
public class TestWorld extends MovieClip
{
public var objects:Array;
public function TestWorld()
{
initWorld();
}
private function initWorld():void
{
objects = new Array();
addEventListener(Event.ENTER_FRAME, loopWorld);
}
private function loopWorld(e:Event):void
{
var object:*;
for (var i:int = 0; i < objects.length; i++) {
MoveObject(objects[i]);
//CheckCollision(i);// doesn't work here for some reason [case 1]
}
CheckCollision(0); //[case 2]
}
private function CheckCollision(i:int):void
{
//test collision
for (var i:int = 0; i < objects.length; i++){ //only use in case 2
var elementA:CollisionObject;
var elementB:CollisionObject;
elementA = objects[i];
for (var j:int = i + 1; j < objects.length; j++) {
if (j <= i){
continue; //j resets each I loop and therefor sets collision to false while it could be true
}
elementB = objects[ j ]// as ObjSprite;
if (elementA.hitTestObject(elementB)) {
elementA.isHit = elementB.isHit = true;
}
}
} //[case 2]
}
private function MoveObject(object:CollisionObject):void
{
object.x += object.vx;
object.y += object.vy;
////////////////////
//check boundaries//
////////////////////
if (object.x > stage.stageWidth)
{
object.vx *= -1;
}else if (object.x < 0)
{
object.vx *= -1;
}else if (object.y > stage.stageHeight)
{
object.vy *= -1;
}else if (object.y < 0)
{
object.vy *= -1;
}
object.isHit = false;// where do we check when it isn't colliding? this seems messy!
}
public function addObject(object:CollisionObject):void
{
objects.push(object);
addChild(object);
}
}
}
还在collisionobject中添加了一个setter和getter(编辑前的部分)。
不知道为什么我不能将checkcollision放在回车框功能的循环中? (当我没有显示碰撞时)。在moveobjects中放置“isHit = false”以重置点击检查也似乎非常混乱。
我似乎无法找出不的对象何时发生碰撞以重置它们。 在hittest上做一个else语句以检查是否没有碰撞不起作用,似乎是合乎逻辑的,因为在hittestcheck中可能只有2个项目发生碰撞。
有什么想法吗?
答案 0 :(得分:0)
我必须查看原始来源才能理解这一点。它在下面,供参考。
这一行
if (j <= i) continue;
是一种排列检查;它基本上确保每个组合只被检查一次,而不是多次。但是,为此,您需要有两个For循环 - 内部循环和外部循环。
你用以下几行做了同样的事情:
for (var j:int = i + 1; i < objects.length; j++) {
尝试使用for循环而不是从零开始的循环。不过,请留下“if j&lt; = i”这一行。我认为这将解决您的问题。 (这两个语句不能在这个循环中共存;如果一起使用,它们将导致你所描述的问题。)
祝你好运。网站的原始资料来源:
for (i = 0; i < myrects.length; i++) {
elementA = myrects[ i ] as ObjMyRect;
for (j = 0; j < myrects.length; j++) {
if (j <= i)
continue;
elementB = myrects[ j ] as ObjMyRect;
if (elementA.rect.x + elementA.rect.width < elementB.rect.x) {
} else if (elementA.rect.x > elementB.rect.x + elementB.rect.width) {
} else if (elementA.rect.y + elementA.rect.height < elementB.rect.y) {
} else if (elementA.rect.y > elementB.rect.y + elementB.rect.height) {
} else {
elementA.isHit = elementB.isHit = true;
}
}
}
(对于它的价值,我认为这个人的代码实际上会检查对象以防止碰撞 - 他应该将“if j&lt; = i”行更改为“if j&lt; i”。你解决了这个问题你原来的循环。)
答案 1 :(得分:0)
在查看他的代码之后,回顾一下你的代码。
这部分是必要的,以确保您不会浪费时间通过循环并重新检查已经比较的项目。
if (j <= i)
continue;
想象一下,阵列中有3个项目,并将项目3与项目0进行比较。然后将项目3与项目1和项目3与项目2进行比较。然后将项目2与项目3进行比较?你已经做到了。您希望将项目2与任何比自身小的项目进行比较,以避免重复。
你的代码接近他的代码,但是你已经用他已经定义的hitTestObject换掉了他的hitTest版本(使用position + dimension)。我只在第一个广场上看到一次击中测试。似乎有些东西......我会在那里放下一些跟踪陈述,看看有什么了。
最后,当您取消注释代码时,它是否有效?