所用平台:cocos creator
所用语言:js
游戏的实现点:
1.可碰撞物体:以白球、其他球、球袋、球杆、球桌分五类,使用creator内置的操作设置可产生碰撞的节点;添加刚体,以节点形状选择刚体形状。以节点属性选择刚体类型是静态还是动态,其中球袋要多设置一项:sensor,即不产生碰撞效果,只产生碰撞监测。
2.球杆的移动、拉伸:球杆要随着白球为中心移动,为不接触白球,要设置最小距离,达到此距离则隐藏。以点击点与白球中心得到一个向量,用得到的向量长度拉伸球杆并改变球杆冲量;向量和水平轴的夹角得到球杆旋转度数。
3.白球进洞操作区别其他球:白球缩小尺寸,其他球则在完全隐藏,这样可以继续对白球的操作,同时,对其他球可以通过每帧执行一个函数:检查球桌上是否还有其他球(除白球)来判断游戏胜利。
代码
cc.Class({
extends: cc.Component,
properties: {
cue: {
type: cc.Node,
default: null,
},
max_dis: 100,
min_dis: 5, // 如果拖动的距离到白球的中心 < 这个距离,那么我们就隐藏球杆,否者的话,显示球杆;
},
start () {
this.body = this.getComponent(cc.RigidBody);
this.cue_inst = this.cue.getComponent("cue");
this.start_x = this.node.x;
this.start_y = this.node.y;
this.node.on(cc.Node.EventType.TOUCH_START, function(e) {
}.bind(this), this);
this.node.on(cc.Node.EventType.TOUCH_MOVE, function(e) {
var w_pos = e.getLocation();
var dst = this.node.parent.convertToNodeSpaceAR(w_pos);
//相对于this.node.parent(canvas)这个为参照物,AR为原点的坐标,(假设)白球移动到移动到世界坐标为 w_pos
//就是去获得点击点的二维向量
var src = this.node.getPosition();//白球二维向量
var dir = cc.pSub(dst, src);//向量相减得到的一个方向向量
var len = cc.pLength(dir);
if (len < this.min_dis) {
this.cue.active = false; // 设置球杆为隐藏;
return;
}
if (len > this.max_dis) {
this.cue.active = false; // 设置球杆为隐藏;
return;
}
this.cue.active = true;
var r = Math.atan2(dir.y, dir.x);//得到弧度
var degree = r * 180 / Math.PI;
degree = 360 - degree;
this.cue.rotation = degree + 90; //旋转球杆
var cue_pos = dst;
var cue_len_half = this.cue.width * 0.1;//本来cue的锚点在中心的,应该是* 0.5的
cue_pos.x += (cue_len_half * dir.x / len);
cue_pos.y += (cue_len_half * dir.y / len);//使得球杆好像在随着点击点的后移向后拉
this.cue.setPosition(cue_pos);
}.bind(this), this);
this.node.on(cc.Node.EventType.TOUCH_END, function(e) {
if(this.cue.active === false) {
return;
}
this.cue_inst.shoot_at(this.node.getPosition());//朝白球方向射击
}.bind(this), this);
this.node.on(cc.Node.EventType.TOUCH_CANCEL, function(e) {
if(this.cue.active === false) {
return;
}
this.cue_inst.shoot_at(this.node.getPosition());
}.bind(this), this);
},
reset: function() {
this.node.scale = 0.35;//当时加入的时候就是0.35
this.node.x = this.start_x;
this.node.y = this.start_y;
this.body.linearVelocity = cc.p(0, 0);//线性转速
this.body.angularVelocity = 0;//角转速
},
onBeginContact: function(contact, selfCollider, otherCollider) {
// 白球有可能,碰球杆,碰球,碰边,球袋
if(otherCollider.node.groupIndex == 2) {
// 隔1秒一种,要把白球放回原处;
this.node.scale = 0;//消失
this.scheduleOnce(this.reset.bind(this), 1);//1秒后白球重置
// end
return;
}
},
// update (dt) {},
});
cc.Class({
extends: cc.Component,
// 属性列表,它将会作为组件实例的数据成员,到组件里面,绑定到我们的编辑器上;
properties: {
value: 1,
},
onLoad () {//每帧比update先
// this,指的就是当前的组件实例
},
start () {//初始化时
// this,指的就是当前的组件实例
this.body = this.getComponent(cc.RigidBody);//同一节点的其他组件
this.start_x = this.node.x;
this.start_y = this.node.y;
},
// dt: 距离上一次刷新的时间;
update (dt) {//每帧
// this,指的就是当前的组件实例
},
reset: function() {
this.node.active = true;
this.node.x = this.start_x;
this.node.y = this.start_y;
this.body.linearVelocity = cc.p(0, 0);
this.body.angularVelocity = 0;
},
onBeginContact: function(contact, selfCollider, otherCollider) {
// 白球有可能,碰球杆,碰球,碰边,球袋
if(otherCollider.node.groupIndex == 2) {
this.node.active = false;
return;
}
},
});
cc.Class({
extends: cc.Component,
properties: {
is_debug: false,
gravity: cc.p(0, -320),
},
// onLoad () {},
onLoad: function() {
cc.director.getPhysicsManager().enabled = true;
if(this.is_debug)
{
var Bits = cc.PhysicsManager.DrawBits;
cc.director.getPhysicsManager().debugDrawFlags = Bits.e_jointBit | Bits.e_shapeBit;
}
else
cc.director.getPhysicsManager().debugDrawFlags = 0;
cc.director.getPhysicsManager().gravity = this.gravity;
},
// update (dt) {},
});
cc.Class({
extends: cc.Component,
properties: {
ball_root: {
type: cc.Node,
default: null,
},
w_ball: {
type: cc.Node,
default: null,
},
},
// onLoad () {},
start () {
this.is_game_started = true;
},
restart_game: function() {
for(var i = 0; i < this.ball_root.childrenCount; i ++) {
var b = this.ball_root.children[i];
b.getComponent("ball").reset();
}
this.w_ball.getComponent("w_ball").reset();
this.is_game_started = true;
},
check_game_over: function() {
for(var i = 0; i < this.ball_root.childrenCount; i ++) {
var b = this.ball_root.children[i];
if(b.active === true) {
return;
}
}
this.is_game_started = false; // game_over;
this.scheduleOnce(this.restart_game.bind(this), 3);
},
update (dt) {
if (!this.is_game_started) {
return;
}
// 是否所有的球都打入进去了;
},
});
挂在球杆节点上
cc.Class({
extends: cc.Component,
properties: {
SHOOT_POWER: 18, // 合适的值就可以了
},
// onLoad () {},
start () {
this.body = this.getComponent(cc.RigidBody);
},
shoot_at: function(dst) {
// 冲量: 给这个球杆一个方向的冲量,矢量,大小,有方向;
// 方向问题: src---> dst;
var src = this.node.getPosition();//此时的球杆头位置
var dir = cc.pSub(dst, src);//dst白球位置
// 大小问题;
var cue_len_half = this.node.width * 0.5;
var len = cc.pLength(dir);
var distance = len - cue_len_half;
// end
var power_x = distance * this.SHOOT_POWER * dir.x / len;
var power_y = distance * this.SHOOT_POWER * dir.y / len;
//对该点施加冲量 applyLinearImpulse(冲量大小向量, 球杆的原点转成世界坐标, true)
this.body.applyLinearImpulse(cc.p(power_x, power_y), this.node.convertToWorldSpaceAR(cc.p(0, 0)), true);
},
onPreSolve: function(contact, selfCollider, otherCollider) {
this.node.active = false;
},
// update (dt) {},
});