[转]格斗游戏的小制作启发

[url]http://bbs.9ria.com/viewthread.php?tid=71537&extra=page%3D1%26amp;orderby%3Ddateline%26amp;filter%3D86400[/url]

我想做个跟恐龙快打差不多的游戏,在舞台上的所有角色,y坐标大的应该挡住y坐标小的,这个效果应该怎么实现?是numChildren结合什么算法吗?



像这样

[img]http://dl.iteye.com/upload/attachment/380194/584a0e14-4c1d-3ce6-8667-1723511dd7bc.gif[/img]


请问楼主一下:
场景应该如何处理,碰撞判断如何处理?


什么叫 场景如何处理?
碰撞判断的话 我用角色脚下的影子进行碰撞检测。


我指的一个是场景的碰撞检测.比如某些地点角色过不去.
另外是攻击检测.


原来场景处理说的是这个
嗯……
本来方向键控制的就是影子,只是让角色的影片剪辑坐标始终跟随影子而已
所以影子能通过碰撞检测的地方,角色也能通过
攻击嘛,我另作了一个方块,平时一直在屏幕外的,一旦按下攻击键,立刻移动到角色拳头上,用这个方块去跟敌人进行碰撞检测
╮(╯▽╰)╭没人教我啊……野孩子就会野方法咯……………………


把所有图形对象放同一数组,按y排序array.sortOn("y"),然后再依次addchild


[img]http://dl.iteye.com/upload/attachment/380196/834b4ebc-05ff-3f7f-9999-a5bcdc7f8f79.png[/img]

这一类的游戏我没有做过,但之前有时间的时候也思考过实现方式.
我理解的实现原理如上图:

首先场景地图的实现方式是基于网格的.紫色是不可到达区域或者是障碍物.
这是场景地图在实现时的数据格式,不考虑具体场景的设计.
可以画出整个场景,然后定义场景的地图数据.

移动方式的检测以绿色线为准.例如黑色是玩家.它在移动时他所处的位置始终处于一个网格范围之内,如果这个网格是可到达区域,那么就移动玩家,否则不移动.
这个根据玩家的x,y位置很容易判断.

攻击点的检测.
灰色快代表攻击点.看一下a,b,c那个敌人被攻击到了?
应该是b,这里的检测不应该是碰撞检测.a和玩家根本不在一条线上,或者说不在同一个水平网格上.c也攻击不到,这个没什么问题.
所以一点建议:
敌人在移动时会更新他所处的网格.而攻击检测则需要根据他与玩家所处的网格的关系来处理.只有先满足网格位置要求,才进行状态检测.
对于敌人的攻击也是如此.这样即使敌人再多,性能上也不会有大问题.

例如,维护一个sprite位置数组:
[
[[玩家],[敌人b],...]
...
]

只需判断玩家相邻网格是否有敌人即可.当然如果攻击范围较长,依次检测相邻第一个,第二个网格等.

至于楼主提到的利用一个攻击块来进行碰撞处理,我认为不是一个好的方式.
而应该根据玩家的状态来处理.
例如:
玩家出拳攻击,那么他会对相邻的一个网格内的敌人产生攻击效果.并不需要检测碰撞.
这类游戏对于角色状态的维护和控制是一个复杂的部分.而且可能不同攻击会有不同的优先级.玩家优于敌人,boss优于玩家等.
这个又和格斗游戏有点关系了.

只想到这么多,希望对你要帮助.







至于显示排序问题,根据那个sprite位置数组来排序即可.



嗯……懂了……优化效率真的很高啊~~~
但是,要通过网格来实现显示排序,如果我需要比较细致的判断y坐标的话,那网格的高岂不是要做的比较小?越精细越小吧……如果判断精度细致到1像素的话,网格貌似不行,构建网格所用的数组,length应该会很大吧……


有一種算法是不用排序的。
不過對於少量的不過100以內的單位來說排序也不慢。



package com.kaixinyy.managers {

import flash.utils.Dictionary;

public class SparseIndexManager

{

//sparse index to object

protected var indexs:Array;

//objects

protected var objects:Dictionary;



public function SparseIndexManager ()

{

indexs = new Array ();

objects = new Dictionary ();

}

//-----------------------------------------------------------------

// Private

//-----------------------------------------------------------------

private function getChildNormalIndex ( child:* ):int {

return indexs.filter ( isNormalIndex ).indexOf ( objects [ child ] );

}

private function isNormalIndex (element:*, index:int, vec:Array ):Boolean {

return element is Index;

}

private function mixSpacing ( from:int ):void {

if ( from == 0 ) return;

var loop:int = from-1;

var array_item:* = indexs [ loop ];

while ( ! ( array_item is Index ) && loop >= 0 ) {

indexs [ loop ] = from;

array_item = indexs [ --loop ];

}

}

//-----------------------------------------------------------------

// Public

//-----------------------------------------------------------------

public function contains ( child:* ):Boolean {

if ( child == null ) {

throw new Error ( "null exception" );

} else {

return objects [ child ] != null;

}

return false;

}

/**

* Add a display object

* @param child A display object that will be add

* @return A index value for *Container

* @see flash.display.*Container

*/

public function addChild ( child:* ):void {

if ( child == null ) {

throw new Error ( "null exception" );

} else if ( contains ( child ) ) {

return;

} else {

// store this child

var i:Index = new Index ( child );

i.sparseindex = indexs.length;

indexs [ indexs.length ] = i;

objects [ child ] = i;

mixSpacing ( indexs.length );

i.normalindex = getChildNormalIndex ( child );

}

}

/**

* Insert a display object

* @param child A display object that will be add

* @param sparseIndex Where to insert

* @return A index value for *Container

* @see flash.display.*Container

*/

public function addChildAt ( child:* , sparseIndex:int ):void {

sparseIndex = Math.abs ( sparseIndex );

if ( child == null ) {

throw new Error ( "null exception" );

} else if ( contains ( child ) ) {

return;

} else {

// store this child

var i:Index = new Index ( child );

//offset

var cut:Array;

function offsetAll ( element:* , index:int , arr:Array ):void {

if ( element is Index ) {

var i:Index = ( Index )( element );

i.normalindex ++;

i.sparseindex ++;

} else {

arr [ index ] ++;

}

}

function offsetIndex ( element:* , index:int , arr:Array ):void {

if ( element is Index ) {

var i:Index = ( Index )( element );

i.normalindex ++;

}

}

if ( indexs [ sparseIndex ] is Index ) {

cut = indexs.splice ( sparseIndex , indexs.length - sparseIndex );;

cut.forEach ( offsetAll );

indexs [ sparseIndex ] = i;

indexs = cut.length==1 ? indexs.concat ( cut[0] ) : indexs.concat ( cut );

} else {

cut = indexs.splice ( sparseIndex , indexs.length - sparseIndex );

cut.forEach ( offsetIndex );

indexs = cut.length==1 ? indexs.concat ( cut[0] ) : indexs.concat ( cut );

indexs [ sparseIndex ] = i;

}

objects [ child ] = i;

mixSpacing ( sparseIndex );

i.sparseindex = sparseIndex;

i.normalindex = getChildNormalIndex ( child );

}

}

/**

* Remove a display object

* @param child A display object that will be remove

* @return A index value for *Container

* @see flash.display.*Container

*/

public function removeChild ( child:* ):void {

if ( child == null ) {

throw new Error ( "null exception" );

} else if ( !contains ( child ) ) {

return;

} else {

var i:Index = objects [ child ];

var next:Index = i.sparseindex == indexs.length - 1 ? null :

indexs [i.sparseindex + 1] is Index ? indexs [i.sparseindex + 1] : indexs [ indexs [i.sparseindex + 1] ];

//if next is null , delete spacing

var loop:int;

if ( next == null ) {

loop = i.sparseindex;

indexs.pop();

while ( !( indexs[--loop] is Index ) && loop >= 0 ) {

indexs.pop();

}

//mix left spacing

} else {

loop = i.sparseindex;

indexs[loop] = next.sparseindex;

while ( !( indexs[--loop] is Index ) && loop >= 0 ) {

indexs[loop] = next.sparseindex;

}

indexs.forEach ( offsetIndex );

function offsetIndex ( element:* , index:int , arr:Array ):void {

if ( element is Index && index > loop ) {

indexs[index].normalindex--;

}

}

}

delete objects [ child ];

}

}

/**

* Remove a display object by sparse index

* @param sparseIndex Witch child will be remove

* @return A index value for *Container

* @see flash.display.*Container

*/

public function removeChildAt ( sparseIndex:int ):void {

sparseIndex = Math.abs ( sparseIndex );

var i:Index = indexs [ sparseIndex ];

if ( i == null ) throw new Error ( "null exception" );

else removeChild ( i.child );

}

/**

* Change a child's sparse index

* @param child A child display object

* @param sparseIndex a sparse index that change to

* @return A index value for *Container

* @see flash.display.*Container

*/

public function setChildIndex ( child:* , sparseIndex:int ):void {

removeChild ( child );

addChildAt ( child , sparseIndex );

}

/**

* get child's normal index or sparse index

* @param child A display object

* @return index

*/

public function getChildIndex ( child:* , isSparseIndex:Boolean = false ):int {

if ( child == null ) {

throw new Error ( "null exception" );

} else if ( !contains ( child ) ) {

} else {

return isSparseIndex ? ( Index )( objects [ child ] ).sparseindex : ( Index )( objects [ child ] ).normalindex;

}

return -1;

}

/**

* Get child by index

* @param sparseIndexOrNormalIndex index value

* @isSparseIndex If use sparse mode

*/

public function getChildByIndex ( sparseIndexOrNormalIndex:int , isSparseIndex:Boolean = false ):* {

sparseIndexOrNormalIndex = Math.abs ( sparseIndexOrNormalIndex );

if ( isSparseIndex ) {

if ( sparseIndexOrNormalIndex > indexs.length - 1 ) return null;

return indexs [ sparseIndexOrNormalIndex ] is Index ?

indexs [ sparseIndexOrNormalIndex ].child : indexs [ indexs [ sparseIndexOrNormalIndex ] ].child;

} else {

function isIndex ( element:* , index:int , arr:Array ):Boolean {

return element is Index && element.normalindex == sparseIndexOrNormalIndex;

}

var indexObjects:Array = indexs.filter( isIndex );

return indexObjects.length > 0 ? indexObjects[0].child : null;

}

}



/**

* Swap two child

*/

public function swapChildren ( child1:* , child2:* ):void {

if ( child1 == null || child2 == null ) {

throw new Error ( "null exception" );

} else if ( !contains ( child1 ) || !contains ( child2 ) ) {

return;

} else {

var i1:Index = objects [ child1 ];

var i2:Index = objects [ child2 ];

i1.child = child2;

i2.child = child1;

objects [ child1 ] = i2;

objects [ child2 ] = i1;

}

}

/**

* Swap two child by sparse index

*/

public function swapChildrenAt ( sparseIndex1:int , sparseIndex2:int ):void {

sparseIndex1 = Math.abs ( sparseIndex1 );

sparseIndex2 = Math.abs ( sparseIndex2 );

var i1:* = indexs [ sparseIndex1 ];

var i2:* = indexs [ sparseIndex2 ];

if ( i1 is Index && i2 is Index ) {

swapChildren ( i1.child , i2.child );

}

}

/**

* Number of children

*/

public function get numChildren ():int {

var i:int = 0;

for ( var key:* in objects ) { i++; }

return i;

}

/**

* All children

*/

public function getChildren ():Array {

var all:Array = [];

for ( var key:* in objects ) { all.push ( key ); };

return all;

}

}

}

//-----------------------------------------------------------------

// Inner class

//-----------------------------------------------------------------

import flash.display.*;



class Index {



internal var child:*;

internal var normalindex:int;

internal var sparseindex:int;

public function Index ( child:* ) {

this.child = child;

this.normalindex = -1;

this.sparseindex = -1;

}

public function toString ():String {

const DEFAULT:String = "["+child.toString()+"]";

return DEFAULT.substr ( 0 , DEFAULT.length-1 ) +

" i:"+normalindex + " si:" + sparseindex + " "+

DEFAULT.substr ( DEFAULT.length-1 , DEFAULT.length );

}

}



如果你要偷懶的使用y作為深度可以使用這個類。
然後addChild(角色, 角色.y)這樣
然後通過getChildIndex(角色)把真實的深度返回來在容器裡面進行addChildAt操作
當角色深度更改的時候重新做一次上述操作。

這種是不排序的因為只需要通過內置的印射關係返回一個實際索引。當然你也看到。實現起來有些繁瑣。
在這種稀疏下標的管理模式裡面,因為索引不是連續的。
因此我需要做很多中間的補位操作讓中間的不存在單位的索引可以直接指向空段的後的第一個非空元素索引。

這個東西我曾在彈出任意深度值的popup中做過測試。是可以正常工作的。
排序有排序的好處。邏輯簡單,不易出錯。
這種雖然實際執行起來效率略高,但較為容易存在問題。


或者楼主可以简单的想 . 角色在舞台里都只会有唯一的深度.当一个角色与另外个角色碰撞了,就交换彼此的深度。这样也可以达到LZ的目的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值