当前位置: 首页 > news >正文

游戏开发面试题1

说说对单例模式的了解

单例模式(Singleton Pattern)是一种设计模式,其目的是确保一个类只有一个实例,并提供一个全局访问点来访问该实例。这在某些情况下非常有用,比如需要一个唯一的配置管理器、日志记录器、或资源管理器。

单例模式的特点

  1. 唯一实例:类内部维护一个唯一实例,确保类的实例只有一个。
  2. 全局访问点:提供一个全局访问点,以便其他类可以通过这个访问点获取该实例。
  3. 延迟实例化:可以延迟创建实例,直到第一次使用时才进行实例化(懒汉模式)。

实现单例模式

饿汉模式

这种方法在类加载时就创建实例,比较简单,但如果实例占用资源较大而且在实际运行中未使用,会造成资源浪费。

class Singleton {private static instance: Singleton = new Singleton();private constructor() { }public static getInstance(): Singleton {return Singleton.instance;}public someMethod() {console.log('Singleton method called.');}
}
// 使用
const singleton = Singleton.getInstance();
singleton.someMethod();
懒汉模式

这种方法在第一次调用 getInstance 方法时才创建实例,适合需要延迟加载的情况。

class Singleton {private static instance: Singleton;private constructor() { }public static getInstance(): Singleton {if (!Singleton.instance) {Singleton.instance = new Singleton();}return Singleton.instance;}public someMethod() {console.log('Singleton method called.');}
}
// 使用
const singleton = Singleton.getInstance();
singleton.someMethod();
线程安全的懒汉模式

在多线程环境中,需要确保实例创建的线程安全性。

class Singleton {private static instance: Singleton;private static lock = new Object();private constructor() { }public static getInstance(): Singleton {if (!Singleton.instance) {synchronized (Singleton.lock) {if (!Singleton.instance) {Singleton.instance = new Singleton();}}}return Singleton.instance;}public someMethod() {console.log('Singleton method called.');}
}// 使用
const singleton = Singleton.getInstance();
singleton.someMethod();

单例模式的优缺点

优点:

  • 控制实例数量:确保类只有一个实例,节省资源。
  • 全局访问:提供全局访问点,方便访问实例。
  • 延迟加载:可以实现延迟加载,减少不必要的资源消耗。

缺点:

  • 扩展性差:单例类难以扩展,尤其是在需要子类化的情况下。
  • 多线程问题:在多线程环境下,需要小心处理实例创建的线程安全问题。
  • 隐藏依赖:使用单例模式可能会隐藏类之间的依赖关系,使代码难以测试和维护。

单例模式的作用,使用单例模式和只创建一个static对象有什么区别

单例模式的作用

单例模式(Singleton Pattern)是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点。单例模式常用于需要一个全局唯一对象的场景,例如:

  1. 配置管理:管理全局的配置参数。
  2. 日志记录器:确保日志记录器实例在整个应用程序中是唯一的。
  3. 资源管理:管理连接池、线程池等资源。
  4. 控制器:在某些设计中,用于控制整个应用程序的行为。

使用单例模式

单例模式的实现有多种方式,最常见的方式包括懒汉式(Lazy Initialization)、饿汉式(Eager Initialization)和双重检查锁定(Double-Check Locking)。以下是C#中的示例代码:

懒汉式(Lazy Initialization)

懒汉式单例模式在第一次需要实例时才创建实例,线程安全问题需要额外处理。

饿汉式(Eager Initialization)

饿汉式单例模式在类加载时创建实例,线程安全但不延迟实例化。

双重检查锁定(Double-Check Locking)

双重检查锁定在保证线程安全的同时,提高了性能。

单例模式与静态类/静态对象的区别

1. 生命周期
  • 单例模式:单例类的实例在首次访问时创建,且在应用程序生命周期内保持存在,直到应用程序结束时销毁。
  • 静态类/静态对象:静态类和静态对象在程序启动时创建,并且一直存在到程序结束。
2. 线程安全
  • 单例模式:单例模式可以通过实现线程安全的实例化方法来保证多线程环境下的安全性。
  • 静态类/静态对象:静态类和静态对象在访问静态成员时,通常不需要考虑实例化的线程安全问题,但需要注意对静态成员的并发访问。
3. 继承和接口实现
  • 单例模式:单例类可以继承其他类和实现接口,支持多态性。
  • 静态类/静态对象:静态类不能继承或实现接口,因为它们不能被实例化,静态类不支持多态性。
4. 延迟初始化
  • 单例模式:可以通过懒汉式实现来延迟初始化,只有在第一次使用时才创建实例。
  • 静态类/静态对象:通常在程序启动时初始化,无法延迟加载。
5. 测试和模拟
  • 单例模式:可以通过依赖注入等方式进行测试和模拟,因为单例类是一个实例对象,可以替换或模拟。
  • 静态类/静态对象:测试和模拟较为困难,因为静态类的成员是全局的,无法轻易替换或模拟。

总结

单例模式和静态类/静态对象各有优缺点,选择使用哪种方式应根据具体需求来决定。如果需要创建一个全局唯一实例,并且希望在多线程环境中安全地进行延迟初始化,同时需要支持继承和接口实现,单例模式是更好的选择。而静态类适合用于工具类或纯静态方法集合,不需要实例化的场景。

如何判断扇形攻击命中

在游戏开发中,扇形攻击是一种常见的攻击方式,比如角色向前方扇形区域内发动攻击。要判断敌人是否被扇形攻击命中,需要考虑敌人的位置是否在扇形区域内。这通常涉及到角度和距离的计算。以下是详细步骤和代码示例:

步骤

  1. 定义扇形参数:包括扇形的中心点、方向、半径和角度。
  2. 计算敌人与扇形中心的距离:判断敌人是否在扇形的半径范围内。
  3. 计算敌人与扇形方向的夹角:判断敌人是否在扇形的角度范围内。

实现细节

1. 定义扇形参数
  • 中心点:扇形的起点位置(攻击者的位置)。
  • 方向:扇形的朝向(攻击者面朝的方向)。
  • 半径:扇形的半径(攻击范围)。
  • 角度:扇形的开口角度。
2. 计算距离

使用欧几里得距离公式计算敌人与扇形中心的距离。如果距离小于或等于扇形的半径,则敌人可能在攻击范围内。

3. 计算夹角

使用向量点积公式计算敌人与扇形方向的夹角。如果夹角小于等于扇形的半角,则敌人在攻击范围内。

代码示例(C#)

以下是一个完整的C#代码示例,展示如何判断敌人是否在扇形攻击范围内。

csharp复制代码using UnityEngine;public class SectorAttack : MonoBehaviour
{public Transform attacker;    // 攻击者的位置和朝向public float attackRadius = 5.0f; // 攻击半径public float attackAngle = 45.0f; // 攻击角度(度数)public Transform target;      // 目标(敌人)void Update(){if (IsTargetInSector(attacker.position, attacker.forward, attackRadius, attackAngle, target.position)){Debug.Log("Target is hit by the sector attack!");}else{Debug.Log("Target is out of the sector attack range.");}}bool IsTargetInSector(Vector3 center, Vector3 forward, float radius, float angle, Vector3 targetPos){// 计算敌人与扇形中心的距离Vector3 directionToTarget = targetPos - center;float distanceToTarget = directionToTarget.magnitude;if (distanceToTarget > radius){return false; // 超出攻击半径}// 计算敌人与扇形方向的夹角float halfAngle = angle / 2.0f;float angleToTarget = Vector3.Angle(forward, directionToTarget);if (angleToTarget > halfAngle){return false; // 超出攻击角度}return true; // 在攻击范围内}
}

解释

  1. attacker.position:攻击者的位置。
  2. attacker.forward:攻击者面朝的方向。
  3. attackRadius:攻击的半径。
  4. attackAngle:攻击的角度。
  5. target.position:目标(敌人)的位置。

IsTargetInSector 方法中:

  • 首先计算敌人与攻击者之间的距离 distanceToTarget,如果距离超过攻击半径,则敌人不在攻击范围内。
  • 然后计算攻击者面朝方向 forward 与敌人方向 directionToTarget 之间的夹角 angleToTarget,如果夹角超过半个攻击角度,则敌人不在攻击范围内。

总结

通过计算敌人与攻击者的距离和夹角,可以有效地判断敌人是否在扇形攻击范围内。这个方法在游戏开发中非常常用,适用于近战攻击、法术范围攻击等各种场景。

详细说下堆排序。

堆的基本概念

  • :堆是一种完全二叉树,可以用数组表示。
  • 最大堆:每个节点的值都大于或等于其子节点的值。
  • 最小堆:每个节点的值都小于或等于其子节点的值。

堆排序通常使用最大堆来实现升序排序。

堆排序的步骤

  1. 构建最大堆:从无序数组构建一个最大堆。

  2. 排序过程:重复以下步骤,直到堆的大小减小到 1:

    • 交换堆顶元素(最大值)与堆的最后一个元素。
    • 减少堆的大小。
    • 对堆顶元素进行堆化操作,使其重新成为最大堆。

构建最大堆

构建最大堆的过程是从最后一个非叶子节点开始,依次向上进行堆化操作。堆化(heapify)是指调整子树,使其满足堆的性质。

堆化操作

堆化操作用于维护堆的性质。假设某个节点的子树已经是堆,但这个节点可能不满足堆的性质。堆化操作会将这个节点与其子节点交换,直到整个子树重新满足堆的性质。

代码实现

以下是用 C# 实现的堆排序算法:

csharp复制代码using System;public class HeapSort
{public static void Sort(int[] array){int n = array.Length;// 构建最大堆for (int i = n / 2 - 1; i >= 0; i--){Heapify(array, n, i);}// 一个个从堆顶取出元素,放到数组末尾,调整堆for (int i = n - 1; i > 0; i--){// 交换堆顶元素和最后一个元素Swap(array, 0, i);// 调整堆Heapify(array, i, 0);}}private static void Heapify(int[] array, int n, int i){int largest = i;int left = 2 * i + 1;int right = 2 * i + 2;// 如果左子节点大于根节点if (left < n && array[left] > array[largest]){largest = left;}// 如果右子节点大于当前最大值if (right < n && array[right] > array[largest]){largest = right;}// 如果最大值不是根节点if (largest != i){Swap(array, i, largest);// 递归堆化受影响的子树Heapify(array, n, largest);}}private static void Swap(int[] array, int i, int j){int temp = array[i];array[i] = array[j];array[j] = temp;}public static void Main(string[] args){int[] array = { 12, 11, 13, 5, 6, 7 };Console.WriteLine("Unsorted array:");Console.WriteLine(string.Join(" ", array));Sort(array);Console.WriteLine("Sorted array:");Console.WriteLine(string.Join(" ", array));}
}

堆排序的时间复杂度

  • 构建最大堆:时间复杂度为 O(n)。
  • 堆化操作:每次堆化的时间复杂度为O(logn),共进行 n−1n-1n−1 次堆化操作,因此时间复杂度为 O(nlogn)。

总体时间复杂度为 O(nlogn)。

堆排序的空间复杂度

堆排序是原地排序算法,只需要常数级的额外空间,因此空间复杂度为 O(1)。

堆排序的特点

  • 时间复杂度稳定:无论数据分布如何,时间复杂度始终为O(nlogn)。
  • 原地排序:不需要额外的数组空间。
  • 不稳定排序:相同元素的相对位置可能会改变。

总结

堆排序是一种高效的排序算法,特别适用于需要原地排序且不关心稳定性的场景。通过构建最大堆和重复堆化操作,堆排序可以在 O(nlogn) 的时间复杂度内对数据进行排序。

相关文章:

游戏开发面试题1

说说对单例模式的了解 单例模式&#xff08;Singleton Pattern&#xff09;是一种设计模式&#xff0c;其目的是确保一个类只有一个实例&#xff0c;并提供一个全局访问点来访问该实例。这在某些情况下非常有用&#xff0c;比如需要一个唯一的配置管理器、日志记录器、或资源管…...

线程池笔记

笔记梳理 前言.PHONYC标准库头文件C/C通用或C特有头文件mkdirc_str()snprintfvsnprintfumaskopen函数可变参数列表va_startva_endfunctionalstatic_castpthread_cond_init_threads.emplace_backstd::bindstd::placeholdersThreadPool(const ThreadPool<T> &tp) dele…...

Go语言基础数据类型、变量及自增语法

本文内容为Go语言的基础数据类型、变量定义和赋值及自增语法介绍。 目录 基础数据类型 变量 先定义后赋值 定义时直接赋值 自动推导定义赋值 平行赋值 自增语法 总结 基础数据类型 int,int8 intl6, int32, int64 uint8... uint64 float32,float64 true/false 变量 …...

ES6-ES13符号:单双引号、变量的解构赋值、占位符 、字符串模版`${} `、扩展运算符...、?,??,_,||=,=,in

原型、this、闭包&#xff0c;for四类循环&#xff0c;ES6-14&#xff08;2023&#xff09;_es6-es14-CSDN博客 目录 查看ES版本 单双引号&#xff1a;无区别 变量的解构赋值&#xff1a;声明变量被数组/对象中的元素赋值 推荐用const&#xff0c;因为是从其他地方获取值 …...

【远景能源25届校招PI测评】题型深度解析与应试策略

摘要&#xff1a; 远景能源作为新能源行业的领军企业&#xff0c;其校园招聘备受瞩目。本文将深入分析25届远景能源校招的PI测评题型&#xff0c;为求职者提供全面的备考指南。 正文&#xff1a; 尊敬的求职者们&#xff0c;您是否正准备迎接远景能源的校招挑战&#xff1f;P…...

关于Qt Creator 使用Qt Quick的Design模式设置

关于使用Qt Quick的Design模式设置&#xff1a; 如描述所言&#xff1a; 如果使用Design模式打开qml文件失败显示如下&#xff1a; 首先确认自己是否安装了Qt Design Studio 如果安装了仍然不显示&#xff0c;则需要勾选下面三个地方才能用Design模式打开.ui.qml文件&#…...

Spring常见问题一:IOC和DI

IOC和DI IOC和DI之间到底是什么关系&#xff1f; 什么是依赖关系&#xff1f;依赖关系会带来什么问题&#xff1f;Spring是怎么来支持依赖注入的&#xff1f; 引言 在现代软件开发中&#xff0c;面向对象编程&#xff08;OOP&#xff09;已经成为主流编程范式。然而&#xff0…...

LabVIEW红外热波图像缺陷检

开发使用LabVIEW开发的红外热波图像缺陷检测系统。该系统结合红外热像仪、工业相机和高效的数据采集硬件&#xff0c;实现对工件表面缺陷的自动检测和分析。通过LabVIEW的强大功能&#xff0c;系统能够实时采集、处理和显示红外热波图像&#xff0c;有效提高了检测的精度和效率…...

c#与欧姆龙PLC通信——如何更改PLC的IP地址

前言 我们有时候需要改变欧姆龙Plc的ip地址,下图有两种更改方式,一种是已知之前Plc设置的Ip地址,还有一种是之前不知道Pl的Ip地址是多少,下面分别做介绍。 1、已知PLC的IP地址的情况下更改地址 假设已知PLC的Ip地址,比如本文中PLC的IP为192.168.1.2,我首先将电脑的IP地…...

[Spring Boot]定时任务因系统时间修改之后无法执行

问题描述 当Spring Boot启动时&#xff0c;当前时间为2024-01-01 00:00:00。 此时你创建了任务&#xff1a; 每10秒钟触发一次定时任务 Scheduled(cron "0/10 * * * * ? ") public void scheduledTask() { }此时你手动修改了系统时间&#xff0c;修改为2023-12-0…...

【棋盘上的战舰】python刷题记录

目录 小前言 思路&#xff1a; 上代码 lucky ending 小前言 经过漫长的停更周期-----1个月 我决定铁血回归&#xff01;&#xff01;&#xff01; 思路&#xff1a; 两层for循环暴力最快了这种小小范围题&#xff0c;主要是第一行和第一列的边界处理&#xff0c;我分为…...

NoSQL 之Redis集群

Redis集群 主从复制 主从复制&#xff08;Replication&#xff09;是 Redis 中一种基本的高可用架构模式&#xff0c;适用于简单的读写分离需求和基本的故障恢复。在主从复制中&#xff0c;一个 Redis 主节点可以拥有多个从节点&#xff0c;主要特点包括&#xff1a; 角色定义&…...

ES13的4个改革性新特性

1、类字段声明 在 ES13 之前,类字段只能在构造函数中声明, ES13 消除了这个限制 // 之前 class Car {constructor() {this.color = blue;this.age = 2...

Flutter EasyRefresh:介绍与使用指南

什么是 Flutter EasyRefresh&#xff1f; Flutter EasyRefresh 是一个强大的下拉刷新和上拉加载组件&#xff0c;用于构建流畅且高效的 Flutter 应用程序。它提供了多种自定义配置和动画效果&#xff0c;使开发者可以轻松实现列表的刷新和加载功能。 主要功能 支持下拉刷新和…...

链表的回文结构(链表的中间节点+反转链表)

链表的回文结构 一.链表的中间节点思路1&#xff1a;暴力求解思路2&#xff1a;快慢指针 二.返回倒数第k个节点思路1&#xff1a;暴力求解思路2&#xff1a;快慢指针 三.反转链表思路1&#xff1a;头插法思路2&#xff1a;反转指针的指向 四.链表的回文结构思路1&#xff1a;利…...

汇编学习基础知识【记录】

前言 又是快乐的学习汇编的一天&#xff0c;时间如白驹过隙&#xff0c;抓紧时间&#xff0c;在学习能力最好的年纪多学习一些知识&#xff0c;朝着美好生活而奋斗&#xff01;哈哈哈 参考文章&#xff1a; https://blog.csdn.net/Z_H_Z_0/article/details/106574292 知识补…...

【持续集成_06课_Jenkins高级pipeline应用】

一、创建项目选择pipeline的风格 它主要是以脚本&#xff08;它自己的语言&#xff09;的方式进行运行&#xff0c;一般由运维去做的事情&#xff0c;作为测试而言。了解即可。 --- 体现形式全部通过脚本去实现&#xff1a;执行之前&#xff08;拉取代码&#xff09;执行&…...

taro小程序terser-webpack-plugin插件不生效(vue2版本)

背景 最近在做公司内部的小程序脚手架&#xff0c;为了兼容老项目和旧项目&#xff0c;做了vue2taro,vue3taro两个模板&#xff0c;发现terser-webpack-plugin在vue2和vue3中的使用方式并不相同&#xff0c;同样的配置在vue3webpack5中生效&#xff0c;但是在vue2webpack4中就…...

games103作业2(未完)

PBD方法 首先是每个质点的力的分析&#xff0c;不考虑碰撞和弹簧弹力的情况下&#xff0c;每个质点受重力的影响&#xff0c;所以需要对每个质点进行速度和位置的重力影响更新。 float t 0.0333f; float damping 0.99f; int[] E; float[] L; Vector3[] V; Vector3 gra…...

避免 WebSocket 连接被拒绝

一、检查服务器配置和权限 (一)确认服务器访问权限 确保您的客户端有访问服务器的合法权限。如果服务器设置了访问控制列表(ACL)或仅允许特定的源(Origin)进行连接,您需要确保客户端的请求来源在允许的范围内。例如,如果服务器只允许来自特定域名的连接,而您的客户端从…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)

题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...

【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?

FTP&#xff08;File Transfer Protocol&#xff09;本身是一个基于 TCP 的协议&#xff0c;理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况&#xff0c;主要原因包括&#xff1a; ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...