● 点击屏幕,根据按住屏幕的时间,进行蓄力,时间越短,发出去的力越小,时间越长,发出去的力越大,超过了最大力,再次从最小里开始,球从篮筐中穿过得1分,否则视为不得分,由于做的是demo,就没有其他限制,可以根据需要尝试修改。
● 游戏就1个场景game,所有游戏的元素都放在这个场景上,场景内3D元素主要3个,3个元素都会挂在弹力和摩擦力设置的PhyMat脚本,PhyMat脚本的主要功能就是设置挂在到对应节点上的所有ColliderComponent的弹力和摩擦力。
● 游戏核心在篮球里,篮球内添加了刚体,因为需要模拟重力效果,添加碰撞体,还有主要的游戏逻辑核心BallCtrl,游戏里的所有核心功能,都在BallCtrl内。
●至于游戏中为什么要自己添加物理材质PhyMat,还有如何添加3D图片的材质,以及需要注意的事项,B老师的视频里都讲的很清楚了,这里就不再赘述。
●主要修改的内容:1.视角调整;2.添加了算分逻辑;3.修改投射角度;4.修改最小最大投掷速度。算分的具体思路是:在篮筐碰撞体正下方放置一个检测是否进球的碰撞体,碰撞体设置小一点,太大了,更容易产生误碰撞,球从篮球框落下的时候,刚好能撞到这个碰撞体,这个需要慢慢调整,本demo里,可能也还有一些问题,可以自行调整。然后检测碰撞体事件,碰撞结束以后,表示得分。
●为了不重复计算,会给篮球添加一个新状态,得分状态,得分检测的碰撞体,在检测到碰撞结束以后,设置为得分状态,下次得分的时候,如果已经是得分状态,就不重复算分。
●球设置有最小最大投掷速度,防止力气过大飞很远,力气很小,球没什么运动距离,这个可以根据观测效果进行调整,为了能够调整投掷力度的大小,到了最大值以后,会重新从最小值开始计算,表现在进度跳上就是,到了最大值以后,又从0往最大值变化。
//------BallCtrl.ts------
import { _decorator, Component, Node, systemEvent, RigidBodyComponent, UITransformComponent, Vec3, SpriteComponent, BoxColliderComponent, LabelComponent } from "cc";
const { ccclass, property } = _decorator;
enum State{
Idle, // 空闲
AddForce, // 加力
ThrowOut, // 抛出
Point, // 得分
}
@ccclass("BallCtrl")
export class BallCtrl extends Component {
@property(UITransformComponent)
private progress: UITransformComponent = null; // 力度显示
@property(BoxColliderComponent)
private colliderPoint: BoxColliderComponent = null; // 得分碰撞体
@property(LabelComponent)
private labelPoint: LabelComponent = null; // 得分显示
private state: State = State.Idle; // 状态
private body: RigidBodyComponent = null; // 刚体
private static MIN_SPEED: number = 6; // 最小速度 (7.6,7.5,7.4)
private static MAX_SPEED: number = 8; // 最大速度
private static ADD_TIME:number = 3; // 加力最长时间
private addDelta: number = 0; // 加力时间
private growSpeed: number = (BallCtrl.MAX_SPEED - BallCtrl.MIN_SPEED) / BallCtrl.ADD_TIME; // 力变化速度
private maxProgress: number = 0; // 最大进度长度值
private point: number = 0; // 得分
private startPos: Vec3 = null; // 开始位置
private testSpeed:number = 7.4;
onLoad(): void{
this.startPos = cc.v3(this.node.position.x, this.node.position.y, this.node.position.z);
this.maxProgress = this.progress.width;
this.state = State.Idle;
this.body = this.node.getComponent(RigidBodyComponent);
this.body.useGravity = false;
this.point = 0;
this.setPercent(0);
systemEvent.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
systemEvent.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
this.colliderPoint.on('onTriggerEnter', this.onTriggerEnter, this);
this.colliderPoint.on('onTriggerStay', this.onTriggerStay, this);
this.colliderPoint.on('onTriggerExit', this.onTriggerExit, this);
}
onTriggerEnter(): void{
// cc.log('onTriggerEnter');
}
onTriggerStay(): void{
// cc.log('onTriggerStay');
}
onTriggerExit():void {
if(this.state != State.ThrowOut){
return;
}
this.point++;
this.labelPoint.string = `得分:${this.point}`;
this.state = State.Point;
}
setPercent(percent: number): void{
this.progress.width = percent * this.maxProgress;
}
onTouchStart(): void{
if(this.state != State.Idle){
return;
}
this.state = State.AddForce;
this.addDelta = 0;
}
onTouchEnd(): void{
if(this.state != State.AddForce){
return;
}
this.state = State.ThrowOut;
this.throwOutBall();
}
throwOutBall():void{
// [7.4, 7.6]
let speed: number = BallCtrl.MIN_SPEED + this.addDelta * this.growSpeed;
// let speed:number = this.testSpeed;
// this.testSpeed += 0.1;
cc.log('speed', speed);
let r:number = Math.PI / 3;
let vy:number = speed * Math.sin(r);
let vz:number = -speed * Math.cos(r);
this.body.useGravity = true;
this.body.setLinearVelocity(cc.v3(0, vy, vz));
this.scheduleOnce(this.resetBall.bind(this), 3);
}
resetBall(): void{
this.body.setLinearVelocity(Vec3.ZERO);
this.body.setAngularVelocity(Vec3.ZERO);
this.body.useGravity = false;
this.node.setPosition(this.startPos);
this.state = State.Idle;
this.setPercent(0);
}
start (): void {
}
update (deltaTime: number): void {
if(this.state != State.AddForce){
return;
}
this.addDelta += deltaTime;
if(this.addDelta > BallCtrl.ADD_TIME){
this.addDelta = 0;
}
// this.addDelta = (this.addDelta > BallCtrl.ADD_TIME)? BallCtrl.ADD_TIME: this.addDelta;
let percent: number = this.addDelta / BallCtrl.ADD_TIME;
this.setPercent(percent);
}
}
//----------PhyMat.ts------------------
import { _decorator, Component, Node, RigidBodyComponent, PhysicMaterial, ColliderComponent } from "cc";
const { ccclass, property } = _decorator;
@ccclass("PhyMat")
export class PhyMat extends Component {
@property
private friction: number = 0; // 摩擦力
@property
private restitution: number = 0; // 弹力
/* class member could be defined like this */
// dummy = '';
/* use `property` decorator if your want the member to be serializable */
// @property
// serializableDummy = 0;
onLoad(): void{
let comps: Array = this.node.getComponents(ColliderComponent) as Array;
let mat = new PhysicMaterial();
mat.friction = this.friction;
mat.restitution = this.restitution;
for(let i = 0; i < comps.length; i++){
comps[i].material = mat;
}
}
start () {
// Your initialization goes here.
}
// update (deltaTime: number) {
// // Your update function goes here.
// }
}
感谢:
本文转载自 https://mp.weixin.qq.com/s/SBcOnsv9pyIft1QnmdG1lw 这篇文章,这里感谢原作者对于技术的分享。
下载:
本文章源码和资源下载地址