用基本图形判定拼接成墙面和物体判定形成场景地图.
地图内有墙壁和障碍物, 角色只能在墙壁和障碍物以外的部分移动.
场景样式妄图模仿某著名游戏…
思路:
– 要有一个地图类, 包含一个泛型容器容纳地图上的所有障碍物.
– 地图类顺序对比某一点(即角色)的位置和容器内所有障碍物的判定, 如果内包则视为碰撞.
– 地图类只做障碍物的判定, 不做描画, 描画应该交给外部位图或矢量图文件. (因为不方便读取文件, 这里仍然在类内部做了一部分描画, 在外部做了另一部分简单描画)
– 要有一个角色类, 为保证简单角色位置虽用矢量保存但移动不做矢量计算.
– 角色先计算移动位置, 判定后再决定是否移动.
[W|S|A|D]:移动角色
[Q]:退出程序
在2.0内制作, 用3.0以上运行可能会报错:
//- --- --- ---
//- public
//- --- --- ---
//-
EcMap pbTheMap=new EcMap(800,400);
EcProtagon pbTheKid=new EcProtagon();
//-
public void setup() {size(320, 240);noStroke();frameRate(32);textAlign(LEFT, TOP);ellipseMode(CENTER);
frame.setTitle("CharaMap");
//--
pbTheMap.ccAddObstacle(new EcRectangleObstacle(0, 0, 800, 300));
pbTheMap.ccAddObstacle(new EcTrangleObstacle(0, 280, 120, 120,'a'));
pbTheMap.ccAddObstacle(new EcTrangleObstacle(680, 280, 120, 120,'b'));
pbTheMap.ccAddObstacle(new EcRectangleObstacle(150, 295, 60, 27));
pbTheMap.ccAddObstacle(new EcRectangleObstacle(450, 295, 60, 27));
pbTheMap.ccAddObstacle(new EcRoundObstacle(350, 350, 50));
//--
pbTheKid.ccInit(pbTheMap,400,350);
pbTheMap.ccRepos(-300, -200);
//--
}//+++
public void draw(){
//--
background(0);
//--
pbTheMap.ccUpdate();
spDrawMapAA(pbTheMap.cmPos.x,pbTheMap.cmPos.y);
pbTheKid.ccUpdate();
//--
}//+++
public void keyPressed() {switch(key){
//--
case 'w':pbTheKid.ccMoveCharactor(0, -1f);pbTheKid.cmHeading=2*PI;break;
case 's':pbTheKid.ccMoveCharactor(0, 1f);pbTheKid.cmHeading=PI;break;
case 'a':pbTheKid.ccMoveCharactor(-1f, 0);pbTheKid.cmHeading=PI*3/2;break;
case 'd':pbTheKid.ccMoveCharactor(1f, 0);pbTheKid.cmHeading=PI/2;break;
//--
case 'q':fsPover();
default:break;
}}//+++
//< <<< <<< <<< <<< <<< Overrided
//* *** *** *** *** ***
//*
//* Operate
//*
//* *** *** *** *** ***
//- --- --- ---
void fsPover(){
exit();
}//+++
void spDrawMapAA(float pxX, float pxY){
stroke(0xFF);noFill();{
rect(pxX+150,pxY+295,60,27);
rect(pxX+450,pxY+295,60,27);
ellipse(pxX+350,pxY+350,50,50);
quad(
pxX+0,pxY+0,
pxX+100,pxY+0,
pxX+100,pxY+300,
pxX+0,pxY+400
);
quad(
pxX+700,pxY+0,
pxX+800,pxY+0,
pxX+800,pxY+400,
pxX+700,pxY+300
);
}noStroke();
fill(0xFF);
text("chair",pxX+455,pxY+305);
text("another\n chair",pxX+155,pxY+292);
text("table",pxX+340,pxY+340);
text("wall",pxX+400,pxY+280);
text("wall",pxX+50,pxY+300);
text("wall",pxX+750,pxY+300);
}//+++
//< <<< <<< <<< <<< <<< operate
//* *** *** *** *** ***
//*
//* Class
//*
//* *** *** *** *** ***
class EcMap{
//--
PVector cmPos, cmDia;
ArrayList<EcObstacle> cmObsatcleList;
float cmCameraRange;
//--
EcMap(int pxW,int pxH){
cmPos=new PVector(0,0);
cmDia=new PVector(pxW, pxH);
cmObsatcleList=new ArrayList<EcObstacle>();
cmCameraRange=100;
}
//--
void ccRepos(int pxX, int pxY){
cmPos.x=(float)pxX;
cmPos.y=(float)pxY;
}
//--
void ccAddObstacle(EcObstacle pxObstacle){
cmObsatcleList.add(pxObstacle);
}
//--
void ccUpdate(){
fill(0xEE,0xAA,0x33);rect(cmPos.x,cmPos.y,cmDia.x,cmDia.y);
if(!cmObsatcleList.isEmpty()){for(EcObstacle itObstacle:cmObsatcleList){
itObstacle.ccRepos((int)cmPos.x, (int)cmPos.y);
itObstacle.ccUpdate();
}}
}
//--
void ccMoveCamera(float pxX, float pxY){
float lpRangeX=cmCameraRange;
float lpRangeY=cmCameraRange;
float lpRangeW=width-(cmCameraRange*2);
float lpRangeH=height-(cmCameraRange*2);
if(pxX<=lpRangeX){cmPos.x+=(lpRangeX-pxX);}
if(pxX>=(lpRangeX+lpRangeW)){cmPos.x-=(pxX-lpRangeX-lpRangeW);}
}
//--
boolean ccIsInRange(float pxX, float pxY){
if(
(pxX>cmPos.x)&&(pxX<cmPos.x+cmDia.x)&&(pxY>cmPos.y)&&(pxY<cmPos.y+cmDia.y)
){
if(!cmObsatcleList.isEmpty()){for(EcObstacle itObstacle:cmObsatcleList){
boolean lpRes=itObstacle.ccIsContaining((int)pxX, (int)pxY);
if(lpRes){return false;}
}}
return true;
}
return false;
}
//--
}//+++
class EcProtagon{
EcMap cmMap;
PVector cmRelatePos;
//--
float cmSpeed;
float cmHeading;
int cmFoot;
//--
EcProtagon(){
cmMap=null;
cmRelatePos=new PVector(0, 0);
cmSpeed=3.3f;
cmHeading=PI/2;
cmFoot=0;
}
//--
void ccInit(EcMap pxMap, int pxX, int pxY){
cmMap=pxMap;
cmRelatePos.x=(float)pxX;
cmRelatePos.y=(float)pxY;
}
//--
void ccUpdate(){
if(cmMap==null){return;}
int lpAbsoX=(int)(cmRelatePos.x+cmMap.cmPos.x);
int lpAbsoY=(int)(cmRelatePos.y+cmMap.cmPos.y);
fill(0xFF);stroke(0);pushMatrix();{
translate(lpAbsoX, lpAbsoY);
rotate(cmHeading);
quad(
-6,-10,
+6,-10,
+12,+10,
-12,+10
);
fill(cmFoot<3?0x33:0xCC);rect(2,2,4,4);
fill(cmFoot<3?0xCC:0x33);rect(-6,2,4,4);
}popMatrix();noStroke();
// ellipse(lpAbsoX, lpAbsoY, 16, 16);
}
//--
void ccMoveCharactor(float pxX, float pxY){
float lpNewPosX=cmRelatePos.x+pxX*cmSpeed;
float lpNewPosY=cmRelatePos.y+pxY*cmSpeed;
if(cmMap.ccIsInRange(lpNewPosX+cmMap.cmPos.x,lpNewPosY+cmMap.cmPos.y)){
cmFoot++;cmFoot&=0x07;
cmRelatePos.x=lpNewPosX;
cmRelatePos.y=lpNewPosY;
cmMap.ccMoveCamera(lpNewPosX+cmMap.cmPos.x, lpNewPosY+cmMap.cmPos.y);
}
}
}//+++
//- --- --- ---
//- Obsatcle
//- --- --- ---
abstract class EcObstacle{
int cmFollowX,cmFollowY;
int cmAbsoX,cmAbsoY;
int cmX,cmY,cmW,cmH;
int cmOnColor;
boolean cmAct;
EcObstacle(){
cmX=cmY=cmW=cmH=9;
cmOnColor=color(0xEE,0xEE,0x33);
cmAct=false;
cmFollowX=0;cmFollowY=0;
cmAbsoX=cmFollowX+cmX;cmFollowY=cmFollowY+cmY;
}
//--
void ccRepos(int pxX, int pxY){
cmFollowX=pxX;
cmFollowY=pxY;
}
void ccRefreshPos(){
cmAbsoX=cmFollowX+cmX;
cmAbsoY=cmFollowY+cmY;
}
//--
abstract void ccUpdate();
abstract boolean ccIsContaining(int pxX, int pxY);
}//+++
class EcRectangleObstacle extends EcObstacle{
//--
EcRectangleObstacle(int pxX, int pxY, int pxW, int pxH) {
super();
cmX=pxX;cmY=pxY;
cmW=pxW;cmH=pxH;
}
//--
@Override void ccUpdate(){
ccRefreshPos();
fill(cmAct?cmOnColor:0x55);
rect(cmAbsoX,cmAbsoY,cmW,cmH);
}
//--
@Override boolean ccIsContaining(int pxX, int pxY){
return (pxX>cmAbsoX)&&(pxX<cmAbsoX+cmW)&&(pxY>cmAbsoY)&&(pxY<cmAbsoY+cmH);
}
//--
}//+++
class EcRoundObstacle extends EcObstacle{
//--
int cmR;
//--
EcRoundObstacle(int pxX, int pxY, int pxD){
super();
cmX=pxX;cmY=pxY;
cmW=cmH=pxD;
cmR=pxD/2;
}
//--
@Override void ccUpdate(){
ccRefreshPos();
fill(cmAct?cmOnColor:0x55);
ellipse(cmAbsoX,cmAbsoY,cmW,cmH);
}
//--
@Override boolean ccIsContaining(int pxX, int pxY){
if(!((pxX>cmAbsoX-cmR)&&(pxX<cmAbsoX+cmR)&&(pxY>cmAbsoY-cmR)&&(pxY<cmAbsoY+cmR))){return false;}else{
PVector lpCenter=new PVector(cmAbsoX,cmAbsoY);
PVector lpTarget=new PVector(pxX,pxY);
return ceil(PVector.dist(lpTarget,lpCenter))<cmR;
}
}
}//+++
class EcTrangleObstacle extends EcObstacle{
//--
char cmMode;
/** *
* @param pxMode_abcd [a]north west point..[b]north east point..
* [c]south east point..[d]south west point
*/
EcTrangleObstacle(int pxX, int pxY, int pxW, int pxH, char pxMode_abcd){
super();
cmX=pxX;cmY=pxY;
cmW=pxW;cmH=pxH;
cmMode=pxMode_abcd;
}
//--
@Override void ccUpdate(){
ccRefreshPos();
fill(cmAct?cmOnColor:0x55);
switch(cmMode){
case 'a':triangle(cmAbsoX, cmAbsoY, cmAbsoX+cmW, cmAbsoY, cmAbsoX, cmAbsoY+cmH);break;
case 'b':triangle(cmAbsoX, cmAbsoY, cmAbsoX+cmW, cmAbsoY, cmAbsoX+cmW, cmAbsoY+cmH);break;
case 'c':triangle(cmAbsoX+cmW, cmAbsoY, cmAbsoX+cmW, cmAbsoY+cmH, cmAbsoX, cmAbsoY+cmH);break;
case 'd':triangle(cmAbsoX, cmAbsoY, cmAbsoX+cmW, cmAbsoY+cmH, cmAbsoX, cmAbsoY+cmH);break;
default:break;
}
}
//--
@Override boolean ccIsContaining(int pxX, int pxY){
if(!((pxX>cmAbsoX)&&(pxX<cmAbsoX+cmW)&&(pxY>cmAbsoY)&&(pxY<cmAbsoY+cmH))){return false;}else{
int lpDPointL=(pxX-cmAbsoX)*cmH/cmW+cmAbsoY;
int lpDPointR=(cmAbsoX+cmW-pxX)*cmH/cmW+cmAbsoY;
switch(cmMode){
case 'a':return pxY<lpDPointR;
case 'b':return pxY<lpDPointL;
case 'c':return pxY>lpDPointR;
case 'd':return pxY>lpDPointL;
default:return false;
}
}
}
//--
}//+++
//EOF
- 本文固定链接: http://iprocessing.cn/2017/12/14/习作cc_直角三角形范围判定应用场景地图墙壁碰撞/
- 转载请注明: constrain 于 Processing编程艺术 发表