我的碰撞检测有问题。基本上当我击中实心瓷砖时,我的角色的身体已经在瓷砖的一半。这是我的代码。
属性wY和wX是我的游戏世界定位。不是舞台定位。 dx和dy是角色行进的速度。第一段代码在游戏循环中。我的角色的焦点集中在x轴上
package com.objects
{
import flash.display.MovieClip;
import com.eapi.EngineApi;
import flash.events.Event;
/**
* ...
* @author Anthony Gordon
*/
public class Engine extends EngineApi
{
public var friction:Number = 0.93;
protected var Heros:Array;
public function Engine(w:Number = 540,h:Number = 360, tw:Number = 50, th:Number = 50)
{
super(w, h, tw, th);
Heros = new Array();
}
override protected function loop(e:Event):void
{
UpdateObjects();
Rules();
CheckHero();
UpDateMap();
}
public function AddHero(g:GameObject):void
{
Heros.push(g);
}
protected function Rules():void
{
//Everything Has friction
for (var i:Number = 0; i < gameObjects.length; i++)
{
var char:GameObject = GameObject(gameObjects[i]);
char.dx *= friction;
//char.dy *= friction;
//Below is the tile positioning of my character
var cgridx:Number = Math.floor(char.wX / tileW);
var cgridy:Number = Math.floor(char.wY/ tileH);
//This is the tile in front of the character
var nextx:Number = Math.floor((char.wX + char.dx) / tileW);
var nexty:Number = Math.floor((char.wY + char.dy) / tileH);
//We assume the character is in the air before we figure it to be false
char.onGround = false;
//I am about to remove the vars from cgrid below. Keep a look out for issues in the future
if (mapHolder[currentMap][nexty][cgridx] == 0 || mapHolder[currentMap][nexty][cgridx] == 2)
{
//If character is falling down
if (char.dy > 0)
{
char.wY = (nexty * tileH) - 1;
cgridy = Math.floor(char.wY / tileH);
char.dy = 0;
char.onGround = true;
}
else if (char.dy < 0)//If character is going up
{
char.wY = (nexty * tileH) + (tileH + 1);
cgridy = Math.floor(char.wY / tileH);
char.dy = 0;
}
}
//mapHolder is a array that holds an array of maps and their tile numbers
if (mapHolder[currentMap][cgridy][nextx] == 2)
{
if (char.dx > 0)//if character is going right
{
char.wX = ((nextx * tileW) - 1);
}
else if (char.dx < 0)// if character is going left
{
char.wX = (nextx * tileW) + (tileW + 1);
}
char.dx = 0;
}
//if character is not on ground then keep faling
if (char.onGround == false)
{
char.dy += .9;
if (char.dy > 30) char.dy = 5;
}
}
}
protected function CheckHero():void
{
var char:Hero = Heros[0];
char.x = char.wX - offsX;
char.y = char.wY - offsY;
if (char.wX < 0)
{
char.wX = 0;
char.dx = 0;
}
if (char.wY < 0)
{
char.wY = 0;
char.dy = 0;
}
offsX = char.wX - (vWidth/2);
offsY = char.wY - (vHeight/2);
if (offsX < 0)
{
offsX = 0;
}
if (offsY < 0)
{
offsY = 0;
}
//If screen hits the world END STOP!!!
if ((offsX + vWidth) > wWidth)
{
offsX = (wWidth - vWidth);
}
if ((offsY + vHeight) > wHeight)
{
offsY = (wHeight - vHeight);
}
/////
//If char hits the end, Stop!!
if (char.wX > wWidth)
{
char.wX = char.wX - wWidth;
char.wX = wWidth;
}
}
}
}
这是我的角色类
package com.objects
{
import flash.display.MovieClip;
import flash.events.*;
/**
* ...
* @author Anthony Gordon
*/
[Embed(source='../../../bin/Assets.swf', symbol='Hero')]
public class Hero extends GameObject
{
private var aKeyPress:Array;
private var jumpDisabled:Boolean = false;
public function Hero()
{
wY = 150;
wX = 90;
speed = .5;
aKeyPress = new Array();
TheGame.sr.addEventListener(KeyboardEvent.KEY_DOWN, keyDownListener);
TheGame.sr..addEventListener(KeyboardEvent.KEY_UP,keyUpListener);
}
private function keyDownListener(e:KeyboardEvent):void {
//trace("down e.keyCode=" + e.keyCode);
aKeyPress[e.keyCode]=true;
}
private function keyUpListener(e:KeyboardEvent):void {
//trace("up e.keyCode=" + e.keyCode);
aKeyPress[e.keyCode]=false;
}
override public function UpdateObject():void
{
Controls();
updatePosition();
}
private function Controls():void
{
wX += dx;
wY += dy;
if (aKeyPress[38])//Key press up
;//vy -= speed;
else if (aKeyPress[40])//Key press down
;//dy += speed;
if (aKeyPress[37])//left
dx -= speed;
else if (aKeyPress[39])//Right
dx += speed;
if (aKeyPress[32]){//space
jump();
}
}//End Controls
private function jump():void
{
if (!jumpDisabled)
{
if (onGround)
{
dy = -15;
jumpDisabled = true;
}
}
else
{
jumpDisabled = false;
}
}
}
}
答案 0 :(得分:2)
您应该在移动前进行测试。
从我上面的代码解析,你移动播放器,然后测试碰撞。如果是这种情况,那么你需要做好准备,如果它碰到任何东西就退出移动(这不是任何有趣的事情或调试)。
更简单地说,您可以调用一个IsBlocked()方法,该方法只是查看位于玩家即将移动方向的磁贴。
if (!player.IsBlocked())
{
player.Move();
}
else
{
player.HandleCollision();
}
答案 1 :(得分:2)
我无法理解你的代码,但是通过制作我的Mega Man引擎,我学到了一些我可以分享的东西。我的碰撞处理方法涉及尝试移动,然后以必要的数量退出。你还需要知道你接近这个区块的方向,这不是一件容易的事。
1)尝试移动。 player.position += player.velocity
2)使用边界框交叉点检查碰撞
2a)找到玩家和块的边界矩形的交集。我不打算给出一个公式,这几乎是微不足道的。 2b)关键点:你必须考虑0高度或0宽度(但不是两个)交叉点作为碰撞!否则你的玩家会在碰撞表面“振动”。
3)使用交叉矩形,找出接近方向。这个算法涉及比较接近速度的斜率和交叉矩形的对角线。
4)基于接近方向(水平或垂直)决定是否退出运动的x或y分量。使用交叉点的高度或宽度作为要还原的数量。
5)存储您的播放器现在被阻挡的事实。请注意,您现在正在触摸该块,但未嵌入其中。这就是为什么一个0大小的交叉点仍然是一个碰撞 - 如果不是,那么下一帧他会认为他没有碰撞再次下降,导致“振动”效果。
至于“已经在牌中途” - 你是不是意外地将玩家的中心点与牌的边缘进行比较?
答案 2 :(得分:1)
嗯,如果不在那里调试是一件很难的事情,但这里有些东西可以解决我的问题。
这两行之间的区别让我感到奇怪:
右转
char.wX = ((nextx * tileW) - 1);
左转
char.wX = (nextx * tileW) + (tileW + 1);
为什么你在第二个结尾处有(tileW + 1)?我认为这些线路是一样的。我不知道为什么第一行也有-1,但是我认为这些行至少应该是相同的。
另外,为什么你在第一时间搞乱dx和dy,这是一个基于图块的东西,而且这个人只能从我看到的一个图块增量移动。你这样做的方式对我来说似乎很奇怪。
答案 3 :(得分:0)
我解决了这个问题。它不是最好的,但比以前好十倍。这就是我做的..
我改变了......
if (mapHolder[currentMap][cgridy][nextx] == 2)
{
if (char.dx > 0)//if character is going right
{
char.wX = ((nextx * tileW) - 1);
}
else if (char.dx < 0)// if character is going left
{
char.wX = (nextx * tileW) + (tileW + 1);
}
char.dx = 0;
}
对此...
if (mapHolder[currentMap][cgridy][right] == 2)
{
char.wX = right * (tileW) - (tileW / 2);
char.dx = 0;
}
else if (mapHolder[currentMap][cgridy][left] == 2)
{
char.wX = right * (tileW) + (tileW / 2);
char.dx = 0;
}
我的角色中心点位于y轴和x轴的中间。所以要做到这一点,我做了以下
if (mapHolder[currentMap][cgridy][left] == 2)
{
char.wX = (left + 1) * (tileW) + (tileW / 2);
char.dx = 0;
}
if (mapHolder[currentMap][cgridy][right] == 2)
{
char.wX = right * (tileW) - (tileW / 2);
char.dx = 0;
}
左右是英雄左右两侧的瓷砖。因为我做了什么,我做了这个(左+ 1)右边的下一个瓷砖。然后我得到它的像素位置乘以它(左+ 1)*(tileW)。我的所有瓷砖焦点都在左上角。所以为了让角色定位在右边。我不得不再添加一半的瓷砖。否则我的英雄的中心点将位于左侧平铺和右侧平铺之间(即左侧+ 1)。对于右边几乎是一样的。但你得到的照片......我希望。