feat: 支持更新相机高度
This commit is contained in:
@@ -52,7 +52,7 @@
|
||||
},
|
||||
"autoReleaseAssets": false,
|
||||
"_globals": {
|
||||
"__id__": 46
|
||||
"__id__": 43
|
||||
},
|
||||
"_id": "58132e64-0171-4c7f-89be-a2984ca7de6b"
|
||||
},
|
||||
@@ -80,9 +80,6 @@
|
||||
{
|
||||
"__id__": 31
|
||||
},
|
||||
{
|
||||
"__id__": 34
|
||||
},
|
||||
{
|
||||
"__id__": 6
|
||||
}
|
||||
@@ -90,13 +87,13 @@
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 43
|
||||
"__id__": 40
|
||||
},
|
||||
{
|
||||
"__id__": 44
|
||||
"__id__": 41
|
||||
},
|
||||
{
|
||||
"__id__": 45
|
||||
"__id__": 42
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -282,7 +279,7 @@
|
||||
"_prefab": null,
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 122.796,
|
||||
"x": 123.77,
|
||||
"y": -26.144,
|
||||
"z": 0
|
||||
},
|
||||
@@ -587,13 +584,13 @@
|
||||
"_restitution": 0,
|
||||
"_offset": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": -2.9,
|
||||
"y": -7.3
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 31.5,
|
||||
"height": 70.3
|
||||
"width": 39.3,
|
||||
"height": 55.7
|
||||
},
|
||||
"_id": "634GiEUhBB8Z1aGzkT6Zyd"
|
||||
},
|
||||
@@ -915,14 +912,14 @@
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "Bg",
|
||||
"_name": "PlayerController",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_children": [],
|
||||
"_active": false,
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 26
|
||||
@@ -959,7 +956,7 @@
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": "9fWIW0nlZOAKYYrvMjuWpy"
|
||||
"_id": "2dBJLKIX9BV4ynG/qUL0Kd"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
@@ -973,18 +970,18 @@
|
||||
"__prefab": null,
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 1080,
|
||||
"height": 2560
|
||||
"width": 100,
|
||||
"height": 100
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": "45vczKBs5CfZpW98yME17u"
|
||||
"_id": "6bjIx8+UNMz47XvRycFFNU"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"__type__": "a1b2cPU5fZ4kKvN7xI0VniQ",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
@@ -993,38 +990,23 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": null,
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
"player": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "361c5873-d797-420e-be65-81c5a8f91215@f9941",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
"camera": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_type": 0,
|
||||
"_fillType": 0,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
"pathfinder": {
|
||||
"__id__": 24
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": null,
|
||||
"_id": "f9zWrrB85EzKBNoudMPMro"
|
||||
"moveSpeed": 300,
|
||||
"mapWidth": 1080,
|
||||
"mapHeight": 2560,
|
||||
"_id": "c1AuAU3IlKnLOzgk9vsBr4"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "PlayerController",
|
||||
"_name": "Manager",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
@@ -1068,100 +1050,6 @@
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": "2dBJLKIX9BV4ynG/qUL0Kd"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 28
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": null,
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 100,
|
||||
"height": 100
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": "6bjIx8+UNMz47XvRycFFNU"
|
||||
},
|
||||
{
|
||||
"__type__": "a1b2cPU5fZ4kKvN7xI0VniQ",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 28
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": null,
|
||||
"player": {
|
||||
"__id__": 6
|
||||
},
|
||||
"camera": {
|
||||
"__id__": 4
|
||||
},
|
||||
"pathfinder": {
|
||||
"__id__": 24
|
||||
},
|
||||
"moveSpeed": 300,
|
||||
"mapWidth": 1080,
|
||||
"mapHeight": 2560,
|
||||
"_id": "c1AuAU3IlKnLOzgk9vsBr4"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "Manager",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 32
|
||||
},
|
||||
{
|
||||
"__id__": 33
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 33554432,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": "faEV0Z9e5HPJZltMJt2Zn9"
|
||||
},
|
||||
{
|
||||
@@ -1170,7 +1058,7 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 31
|
||||
"__id__": 28
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": null,
|
||||
@@ -1192,7 +1080,7 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 31
|
||||
"__id__": 28
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": null,
|
||||
@@ -1214,25 +1102,25 @@
|
||||
},
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 35
|
||||
"__id__": 32
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 35
|
||||
},
|
||||
{
|
||||
"__id__": 36
|
||||
},
|
||||
{
|
||||
"__id__": 37
|
||||
},
|
||||
{
|
||||
"__id__": 38
|
||||
},
|
||||
{
|
||||
"__id__": 39
|
||||
},
|
||||
{
|
||||
"__id__": 40
|
||||
},
|
||||
{
|
||||
"__id__": 41
|
||||
},
|
||||
{
|
||||
"__id__": 42
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -1271,16 +1159,16 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 34
|
||||
"__id__": 31
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 36
|
||||
"__id__": 33
|
||||
},
|
||||
{
|
||||
"__id__": 37
|
||||
"__id__": 34
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -1319,7 +1207,7 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 35
|
||||
"__id__": 32
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": null,
|
||||
@@ -1341,7 +1229,7 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 35
|
||||
"__id__": 32
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": null,
|
||||
@@ -1403,7 +1291,7 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 34
|
||||
"__id__": 31
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": null,
|
||||
@@ -1425,7 +1313,7 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 34
|
||||
"__id__": 31
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": null,
|
||||
@@ -1464,7 +1352,7 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 34
|
||||
"__id__": 31
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": null,
|
||||
@@ -1495,7 +1383,7 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 34
|
||||
"__id__": 31
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": null,
|
||||
@@ -1523,7 +1411,7 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 34
|
||||
"__id__": 31
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": null,
|
||||
@@ -1616,28 +1504,28 @@
|
||||
{
|
||||
"__type__": "cc.SceneGlobals",
|
||||
"ambient": {
|
||||
"__id__": 47
|
||||
"__id__": 44
|
||||
},
|
||||
"shadows": {
|
||||
"__id__": 48
|
||||
"__id__": 45
|
||||
},
|
||||
"_skybox": {
|
||||
"__id__": 49
|
||||
"__id__": 46
|
||||
},
|
||||
"fog": {
|
||||
"__id__": 50
|
||||
"__id__": 47
|
||||
},
|
||||
"octree": {
|
||||
"__id__": 51
|
||||
"__id__": 48
|
||||
},
|
||||
"skin": {
|
||||
"__id__": 52
|
||||
"__id__": 49
|
||||
},
|
||||
"lightProbeInfo": {
|
||||
"__id__": 53
|
||||
"__id__": 50
|
||||
},
|
||||
"postSettings": {
|
||||
"__id__": 54
|
||||
"__id__": 51
|
||||
},
|
||||
"bakedWithStationaryMainLight": false,
|
||||
"bakedWithHighpLightmap": false
|
||||
|
||||
@@ -4,115 +4,117 @@ const { ccclass, property } = _decorator;
|
||||
@ccclass('CameraFollow')
|
||||
export class CameraFollow extends Component {
|
||||
|
||||
@property(Node)
|
||||
target: Node | null = null; // 要跟随的目标(玩家)
|
||||
@property(Node)
|
||||
target: Node | null = null; // 要跟随的目标(玩家)
|
||||
|
||||
@property({ range: [0.1, 10] })
|
||||
followSpeed: number = 5.0; // 跟随速度
|
||||
@property({ range: [0.1, 10] })
|
||||
followSpeed: number = 5.0; // 跟随速度
|
||||
|
||||
@property(Vec3)
|
||||
offset: Vec3 = new Vec3(0, 0, 10); // 相机相对目标的偏移
|
||||
@property(Vec3)
|
||||
offset: Vec3 = new Vec3(0, 0, 10); // 相机相对目标的偏移
|
||||
|
||||
@property({ range: [0, 1] })
|
||||
smoothness: number = 0.1; // 平滑度,0为瞬间跟随,1为最慢跟随
|
||||
@property({ range: [0, 1] })
|
||||
smoothness: number = 0.1; // 平滑度,0为瞬间跟随,1为最慢跟随
|
||||
|
||||
@property
|
||||
mapWidth: number = 1080; // 地图宽度
|
||||
@property
|
||||
mapWidth: number = 1080; // 地图宽度
|
||||
|
||||
@property
|
||||
mapHeight: number = 2560; // 地图高度
|
||||
@property
|
||||
mapHeight: number = 2560; // 地图高度
|
||||
|
||||
private camera: Camera | null = null;
|
||||
private camera: Camera | null = null;
|
||||
|
||||
onLoad() {
|
||||
// 获取相机组件
|
||||
this.camera = this.getComponent(Camera);
|
||||
if (!this.camera) {
|
||||
console.error('CameraFollow: 未找到Camera组件');
|
||||
}
|
||||
onLoad() {
|
||||
// 获取相机组件
|
||||
this.camera = this.getComponent(Camera);
|
||||
|
||||
this.camera.orthoHeight = 500
|
||||
if (!this.camera) {
|
||||
console.error('CameraFollow: 未找到Camera组件');
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.target) {
|
||||
// 初始化相机位置
|
||||
const initialPos = this.target.position.clone();
|
||||
initialPos.add(this.offset);
|
||||
this.node.position = initialPos;
|
||||
}
|
||||
start() {
|
||||
if (this.target) {
|
||||
// 初始化相机位置
|
||||
const initialPos = this.target.position.clone();
|
||||
initialPos.add(this.offset);
|
||||
this.node.position = initialPos;
|
||||
}
|
||||
}
|
||||
|
||||
update(deltaTime: number) {
|
||||
if (!this.target) return;
|
||||
update(deltaTime: number) {
|
||||
if (!this.target) return;
|
||||
|
||||
// 计算目标位置
|
||||
const targetPosition = this.target.position.clone();
|
||||
targetPosition.add(this.offset);
|
||||
// 计算目标位置
|
||||
const targetPosition = this.target.position.clone();
|
||||
targetPosition.add(this.offset);
|
||||
|
||||
// 应用地图边界限制
|
||||
const clampedPosition = this.clampCameraPosition(targetPosition);
|
||||
// 应用地图边界限制
|
||||
const clampedPosition = this.clampCameraPosition(targetPosition);
|
||||
|
||||
// 使用插值实现平滑跟随
|
||||
const currentPosition = this.node.position;
|
||||
const newPosition = new Vec3();
|
||||
// 使用插值实现平滑跟随
|
||||
const currentPosition = this.node.position;
|
||||
const newPosition = new Vec3();
|
||||
|
||||
// 根据平滑度设置插值速度
|
||||
const lerpFactor = Math.min(1.0, this.followSpeed * deltaTime * (1 - this.smoothness + 0.1));
|
||||
// 根据平滑度设置插值速度
|
||||
const lerpFactor = Math.min(1.0, this.followSpeed * deltaTime * (1 - this.smoothness + 0.1));
|
||||
|
||||
Vec3.lerp(newPosition, currentPosition, clampedPosition, lerpFactor);
|
||||
this.node.position = newPosition;
|
||||
Vec3.lerp(newPosition, currentPosition, clampedPosition, lerpFactor);
|
||||
this.node.position = newPosition;
|
||||
}
|
||||
|
||||
// 限制相机位置在地图边界内
|
||||
private clampCameraPosition(position: Vec3): Vec3 {
|
||||
if (!this.camera) return position;
|
||||
|
||||
// 获取屏幕可见区域大小
|
||||
const visibleSize = view.getVisibleSize();
|
||||
|
||||
// 计算相机能看到的世界区域的一半
|
||||
const halfCameraWidth = visibleSize.width * 0.5;
|
||||
const halfCameraHeight = visibleSize.height * 0.5;
|
||||
|
||||
// 计算地图边界(地图锚点为0.5,0.5,所以范围是-mapWidth/2到+mapWidth/2)
|
||||
const mapHalfWidth = this.mapWidth * 0.5;
|
||||
const mapHalfHeight = this.mapHeight * 0.5;
|
||||
|
||||
// 计算相机位置的边界(确保相机边缘不超出地图边界)
|
||||
const minX = -mapHalfWidth + halfCameraWidth;
|
||||
const maxX = mapHalfWidth - halfCameraWidth;
|
||||
const minY = -mapHalfHeight + halfCameraHeight;
|
||||
const maxY = mapHalfHeight - halfCameraHeight;
|
||||
|
||||
// 限制相机位置
|
||||
const clampedPosition = position.clone();
|
||||
clampedPosition.x = Math.max(minX, Math.min(maxX, position.x));
|
||||
clampedPosition.y = Math.max(minY, Math.min(maxY, position.y));
|
||||
|
||||
return clampedPosition;
|
||||
}
|
||||
|
||||
// 设置跟随目标
|
||||
setTarget(target: Node) {
|
||||
this.target = target;
|
||||
if (target) {
|
||||
const initialPos = target.position.clone();
|
||||
initialPos.add(this.offset);
|
||||
this.node.position = initialPos;
|
||||
}
|
||||
}
|
||||
|
||||
// 限制相机位置在地图边界内
|
||||
private clampCameraPosition(position: Vec3): Vec3 {
|
||||
if (!this.camera) return position;
|
||||
// 设置偏移量
|
||||
setOffset(offset: Vec3) {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
// 获取屏幕可见区域大小
|
||||
const visibleSize = view.getVisibleSize();
|
||||
// 瞬间移动到目标位置
|
||||
snapToTarget() {
|
||||
if (!this.target) return;
|
||||
|
||||
// 计算相机能看到的世界区域的一半
|
||||
const halfCameraWidth = visibleSize.width * 0.5;
|
||||
const halfCameraHeight = visibleSize.height * 0.5;
|
||||
|
||||
// 计算地图边界(地图锚点为0.5,0.5,所以范围是-mapWidth/2到+mapWidth/2)
|
||||
const mapHalfWidth = this.mapWidth * 0.5;
|
||||
const mapHalfHeight = this.mapHeight * 0.5;
|
||||
|
||||
// 计算相机位置的边界(确保相机边缘不超出地图边界)
|
||||
const minX = -mapHalfWidth + halfCameraWidth;
|
||||
const maxX = mapHalfWidth - halfCameraWidth;
|
||||
const minY = -mapHalfHeight + halfCameraHeight;
|
||||
const maxY = mapHalfHeight - halfCameraHeight;
|
||||
|
||||
// 限制相机位置
|
||||
const clampedPosition = position.clone();
|
||||
clampedPosition.x = Math.max(minX, Math.min(maxX, position.x));
|
||||
clampedPosition.y = Math.max(minY, Math.min(maxY, position.y));
|
||||
|
||||
return clampedPosition;
|
||||
}
|
||||
|
||||
// 设置跟随目标
|
||||
setTarget(target: Node) {
|
||||
this.target = target;
|
||||
if (target) {
|
||||
const initialPos = target.position.clone();
|
||||
initialPos.add(this.offset);
|
||||
this.node.position = initialPos;
|
||||
}
|
||||
}
|
||||
|
||||
// 设置偏移量
|
||||
setOffset(offset: Vec3) {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
// 瞬间移动到目标位置
|
||||
snapToTarget() {
|
||||
if (!this.target) return;
|
||||
|
||||
const targetPosition = this.target.position.clone();
|
||||
targetPosition.add(this.offset);
|
||||
const clampedPosition = this.clampCameraPosition(targetPosition);
|
||||
this.node.position = clampedPosition;
|
||||
}
|
||||
const targetPosition = this.target.position.clone();
|
||||
targetPosition.add(this.offset);
|
||||
const clampedPosition = this.clampCameraPosition(targetPosition);
|
||||
this.node.position = clampedPosition;
|
||||
}
|
||||
}
|
||||
@@ -85,12 +85,24 @@ export class PlayerController extends Component {
|
||||
const normalizedX = screenPos.x - centerX;
|
||||
const normalizedY = screenPos.y - centerY;
|
||||
|
||||
// 获取相机的正交高度
|
||||
const orthoHeight = this.camera.orthoHeight;
|
||||
|
||||
// 计算屏幕坐标到世界坐标的缩放比例
|
||||
// 屏幕高度的一半对应 orthoHeight 的世界单位
|
||||
const scaleY = orthoHeight / (visibleSize.height * 0.5);
|
||||
const scaleX = scaleY; // 保持宽高比一致
|
||||
|
||||
// 将屏幕坐标转换为世界坐标(相对于相机中心)
|
||||
const worldOffsetX = normalizedX * scaleX;
|
||||
const worldOffsetY = normalizedY * scaleY;
|
||||
|
||||
// 考虑相机的位置偏移
|
||||
const cameraPos = this.camera.node.position;
|
||||
|
||||
// 计算世界坐标
|
||||
const worldX = normalizedX + cameraPos.x;
|
||||
const worldY = normalizedY + cameraPos.y;
|
||||
// 计算最终的世界坐标
|
||||
const worldX = worldOffsetX + cameraPos.x;
|
||||
const worldY = worldOffsetY + cameraPos.y;
|
||||
|
||||
return new Vec3(worldX, worldY, 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user